Compare commits

...

49 Commits

Author SHA1 Message Date
Jissin Mathew 19acbed1fd fix: cleanup and small improvements
- added empty check in inventory alerts
- corrected parts cost calculation
- removed unused getUser method
- updated default admin password
- fixed missing includes in menus
- cleaned up MenuHelper comments
2026-05-25 20:14:01 +05:30
Jissin Mathew 9ee392ab3c Merge branch 'feature' into feature-1553-1598 2026-05-25 20:07:05 +05:30
Avinash Rajesh ef5125d445 Merged PR 1044: Admin-Management-1560, Inventory-Management-1552
**Admin Management**
**ADM001 - Add Technician:** Allows admins to create technician accounts for job assignments.
**ADM002 - Remove Technician or Customer:** Allows admins to remove technician or customer accounts from the system.
**ADM003 - Login:** Allows admins and technicians to securely log in to access system features.
**ADM004 - Logout:** Allows admins and technicians to securely log out of the system.
**ADM005 - Change Password:** Allows admins and technicians to update their account password for security.
**ADM006 - Create Combo Package:** Allows admins to create discounted combo service packages for customers.
**ADM007 - Remove Combo Package:** Allows admins to remove outdated combo packages from the system.

**Inventory Management**
**INV001 - View Stock Levels:** Allows admins to view current inventory stock levels and track spare part availability.
**INV002 - Add Stock:** Allows admins to add new inventory items or update stock quantities.
**INV003 - Remove Stock:** Allows admins to remove inventory items from the system.
**INV004 - Check Stock Availability:** Allows admins to check the availability of a specific stock item.

Related work items: #1552, #1560, #1573, #1574, #1575, #1576, #1582, #1583, #1584, #1585, #1586, #1587, #1588, #1668, #1669, #1672, #1673
2026-05-25 19:00:53 +05:30
joelthomastrenser 53c768bde9 Merge branch 'feature' into feature-1552-1560 2026-05-25 18:58:55 +05:30
Avinash Rajesh 45d4f693b6 Fix PR review comments and refactor menu helper logic
Changes:

- Added missing include for MenuHelper.h in project and AdminMenu
- Fixed typo in variable name inventoryIems to inventoryItems in Controller.cpp
- Removed stray semicolon from include in Controller.h
- Cleaned up duplicate comments in Controller.cpp description header
- Minor formatting adjustments with blank lines after headers in multiple files
- Updated ServiceManagementService notification message to remove informal wording
- Refactored AdminMenu::changePassword to use changePasswordHelper
- Added util::clear() call at start of viewStockLevels
- Removed redundant helper functions from AdminMenu.cpp and moved to shared helpers
- Fixed bug in removeInventoryItem to use activeItems instead of inventoryItems
- Enhanced createComboPackages to enforce selection of two distinct services
- General comment cleanup and formatting consistency across headers and implementation files
2026-05-25 17:32:17 +05:30
Jissin Mathew 1c717bb9fa Fix PR review comments
Changes:
    1. Added missing include for MenuHelper.h in project, AdminMenu, and CustomerMenu.
    2. Updated PaymentManagementService::completePayment to guard against duplicate completion by checking status before updating.
    3. Enhanced ServiceManagementService::createJobCard with null checks for inventory items and safe stock decrement logic.
    4. Added null check for job card creation in ServiceManagementService and throw runtime error if creation fails.
    5. Refactored ServiceManagementService::removeService to use m_dataStore.getServices() reference instead of getServices() copy.
    6. Renamed helper function hasAllJobCardsinServiceBookingCompleted to hasCompletedAllJobs for clarity and updated usage in completeJob.
    7. Fixed ServiceJobStatus string conversion in Enums.h to correctly return "PENDING" instead of "STARTED".
    8. Added support for parsing "PENDING" string to ServiceJobStatus::PENDING in Enums.h.
    9. Cleaned up AdminMenu.cpp by removing redundant static helper functions (listServiceBookings, selectPendingServiceBookings, listAvailableTechnicians, selectTechnician, selectInventoryItems, selectServicesToRemove).
    10. Replaced removed helpers with shared MenuHelper usage and added util::pressEnter() calls for consistent user flow.
    11. Simplified CustomerMenu.cpp by removing redundant static helpers (selectInvoiceFromUserForPayment, selectPaymentMode, displayInvoices) and moved logic to shared helpers.
    12. General formatting and comment cleanup across AdminMenu.cpp and CustomerMenu.cpp for consistency.
2026-05-25 17:31:20 +05:30
joelthomastrenser 5c23c1b9a1 Merged PR 1043: Customer-Management-1551, Notification-Management-1561, File-Management-1708
**Customer Management**
* **CUS001 - Login:** Allows customers to securely log in using valid username and password.
* **CUS002 - Logout:** Allows customers to safely log out of the system.
* **CUS003 - Change Password:** Allows customers to update their account password for security.
* **CUS004 - Customer Registration:** Allows new customers to create an account by entering personal and vehicle details.
* **CUS005 - Update Customer Details:** Allows customers to modify their saved personal information.
* **CUS006 - Select Individual Service:** Allows customers to choose and book a single vehicle service.
* **CUS007 - Select Combo Package:** Allows customers to choose and book a combo package with multiple services.

**Notification Management**
* **NOT001 - View Customer Notifications:** Allows customers to view and manage their notifications for important updates.
* **NOT002 - View Admin Notifications:** Allows admins to view and manage their notifications for important updates.
* **NOT003 - View Technician Notifications:** Allows technicians to view and manage their notifications for important updates.
* **NOT004 - Low Stock Alert:** Sends notifications to admins when inventory stock falls below the threshold.
* **NOT005 - Payment Reminder:** Sends payment reminder notifications to customers for unpaid invoices.
* **NOT006 - Configure Notifications:** Allows customers to manage notification preferences for selected services.

**File Management**
* **File Management:** Handles file-related operations such as storing, retrieving, updating, and managing files within the system.

Related work items: #1551, #1561, #1563, #1564, #1568, #1569, #1570, #1571, #1572, #1592, #1593, #1594, #1595, #1596, #1597, #1624, #1626, #1648, #1649, #1708, #1709
2026-05-25 16:05:40 +05:30
Jissin Mathew 6392191c14 Merge branch 'feature-payment-management' into feature-1553-1598 2026-05-25 12:11:20 +05:30
Avinash Rajesh c44b8ffd4e Merge branch 'feature-inventory-management' into feature-1552-1560 2026-05-25 12:02:30 +05:30
Avinash Rajesh c5f87a0c68 Add standardized documentation headers 2026-05-25 10:54:35 +05:30
Jissin Mathew f1d146a37c Add documentation headers across system modules 2026-05-22 13:21:51 +05:30
Jissin Mathew 0519690043 Add documentation headers across system modules 2026-05-22 13:11:11 +05:30
Avinash Rajesh 6ca659c573 Add standardized documentation headers 2026-05-22 11:27:49 +05:30
Avinash Rajesh 7e9cc27f1c Merge branch 'feature-inventory-management-inv004' into feature-inventory-management 2026-05-21 20:14:03 +05:30
Avinash Rajesh 1377d5fb39 Merge branch 'feature-inventory-management-inv003' into feature-inventory-management 2026-05-21 20:11:55 +05:30
Avinash Rajesh d33f0aa8dc Merge branch 'feature-inventory-management-inv002' into feature-inventory-management 2026-05-21 20:09:53 +05:30
Avinash Rajesh 337fb00e1f Merge branch 'feature-admin-management-menu' into feature-admin-management 2026-05-21 19:41:39 +05:30
Avinash Rajesh 33a3677f6e Merge branch 'feature-admin-management-adm007' into feature-admin-management 2026-05-21 19:22:52 +05:30
Avinash Rajesh 3a8db0cdae Merge branch 'feature-admin-management-adm006' into feature-admin-management 2026-05-21 19:16:50 +05:30
Avinash Rajesh 7c993521a2 Merge branch 'feature-admin-management-adm005' into feature-admin-management 2026-05-21 19:10:58 +05:30
Avinash Rajesh ef2fa6d521 Merge branch 'feature-admin-management-adm004' into feature-admin-management 2026-05-21 19:06:44 +05:30
Avinash Rajesh c8647eedd9 Merge branch 'feature-admin-management-adm003' into feature-admin-management 2026-05-21 19:02:57 +05:30
Avinash Rajesh 665d9192fa Merge branch 'feature-admin-management-adm002' into feature-admin-management 2026-05-21 18:55:23 +05:30
Jissin Mathew 0adb864329 Merge branch 'feature-service-management-ser005' into feature-service-management 2026-05-21 18:34:12 +05:30
Jissin Mathew a3ad4d2e00 Merge branch 'feature-payment-management-pay003' into feature-payment-management 2026-05-21 18:11:09 +05:30
Jissin Mathew 86fd32bd2b Merge branch 'feature-service-management-ser004' into feature-service-management 2026-05-21 17:26:27 +05:30
Jissin Mathew fceb1cbec6 Merge branch 'feature-service-management-ser003' into feature-service-management 2026-05-21 17:10:53 +05:30
Jissin Mathew 53ff70a85f Merge branch 'feature-service-management-ser002' into feature-service-management 2026-05-21 16:54:07 +05:30
Jissin Mathew 4a4309d585 Merge branch 'feature-payment-management-pay002' into feature-payment-management 2026-05-21 16:20:42 +05:30
Jissin Mathew 61f70a54f6 Implement Generate Invoice
<UserStory> PAY001: Generate Invoice </UserStory>

<Changes>
    1. Added Utility.h to project configuration for supporting invoice generation utilities.
    2. Updated Invoice model to use string-based keys for parts mapping instead of integer keys.
    3. Implemented PaymentManagementService::generateInvoice to aggregate labour cost, parts cost, and apply discounts.
    4. Integrated invoice creation with Factory to instantiate Invoice objects and persist them into datastore.
    5. Enhanced Enums with PaymentMode::NOTSET to handle default invoice state.
</Changes>

<Test>

 Acceptance Criteria:
 1. Invoice auto-generates for each service booking once jobs are completed.
 2. Invoice shows a clear breakdown of charges including labour cost, parts cost, discount, and total amount.

 Precondition:
  1. Service booking exists with at least one service and required inventory items.
  2. Datastore is available for storing invoices.
  3. Payment mode and status enums are properly configured.

 Steps:
  1. Complete all jobs in a service booking.
    - Verify that PaymentManagementService::generateInvoice is triggered.
  2. Check datastore for newly created invoice.
    - Verify that invoice contains booking ID, labour cost, parts cost, discount, and total amount.
  3. Inspect invoice details.
    - Verify that breakdown of charges is accurate and discount is applied correctly.
  4. Confirm invoice status.
    - Verify that invoice is created with PaymentMode::NOTSET and PaymentStatus::PENDING.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 16:05:10 +05:30
Avinash Rajesh d161ac313c Implement Change Password Functionality
<UserStory> ADM005: Change Password </UserStory>

<Changes>
    1. Added AuthenticationManagementService::changePassword to update the authenticated user’s password with validation.
    2. Integrated Controller::changePassword to delegate password update requests to AuthenticationManagementService.
    3. Enhanced AdminMenu::changePassword to prompt for new password, validate strength using Validator, and confirm update.
    4. Added error handling to prevent password change when no user is logged in.
    5. Provided user feedback messages for invalid password attempts and successful updates.
</Changes>

<Test>

  Precondition:
  1. Admin is logged into the system.
  2. AuthenticationManagementService maintains active session.
  3. Validator is available for password strength checks.

  Steps:
  1. Navigate to Admin Menu and select "Change Password".
  2. Enter old password incorrectly.
    - Verify that system rejects the attempt and displays error.
  3. Enter new password that fails validation (length/complexity).
    - Verify that system rejects with "Error: Password is not strong enough!".
  4. Enter valid old password and strong new password.
    - Verify that system confirms "Password changed successfully" and updates the user’s password.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:12:16 +05:30
Jissin Mathew 461857f971 Implement View Invoices for Customer
<UserStory> PAY003: View Invoices </UserStory>

<Changes>
    1. Added CustomerMenu::viewInvoices to fetch invoices via Controller and display them to the customer.
    2. Implemented displayInvoices helper to show invoice details including booking, vehicle, technician, discount, total amount, invoice date, and payment status.
    3. Enhanced invoice display to include a tabular breakdown of inventory items (ItemName, Quantity, Price) used in the service.
    4. Updated ServiceBooking to store assigned technician as a const User* for richer technician details in invoice output.
</Changes>

<Test>

 Acceptance Criteria:
 1. Invoice details should show total cost and discounts.
 2. Invoice details should show list of parts used.

 Precondition:
  1. Customer is logged into the system.
  2. At least one invoice exists for the customer in the datastore.
  3. Inventory items are linked to the invoice.

 Steps:
  1. Navigate to Customer menu and choose "View Invoices".
    - Verify that the system lists invoice details including booking ID, vehicle info, technician, discount, total amount, invoice date, and payment status.
  2. Check the parts list under each invoice.
    - Verify that inventory items are displayed in tabular form with ItemName, Quantity, and Price.
  3. Confirm that discounts and total cost are shown correctly.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 15:09:16 +05:30
Avinash Rajesh fa08d4a90f Implement Login Functionality
<UserStory> ADM003: Login </UserStory>

<Changes>
    1. Added credential input handling in UserInterface::login with username and password prompts.
    2. Integrated Controller::login to validate credentials and retrieve authenticated user.
    3. Implemented role-based menu navigation: Admin → AdminMenu, Technician → TechnicianMenu, Customer → CustomerMenu.
    4. Added error handling for invalid credentials and unknown user types with clear feedback messages.
    5. Included util::clear for screen refresh and structured output formatting during login.
</Changes>

<Test>

  Precondition:
  1. Valid user accounts exist in the system (Admin, Technician, Customer).
  2. Controller is connected to UserManagementService for authentication.
  3. UserInterface is initialized with role-specific menus.

  Steps:
  1. Launch UserInterface and select "Login".
  2. Enter incorrect username or password.
    - Verify that system displays "Error: Invalid Username or Password".
  3. Enter valid admin credentials.
    - Verify that AdminMenu is displayed successfully.
  4. Enter valid technician or customer credentials.
    - Verify that TechnicianMenu or CustomerMenu is displayed accordingly.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:09:04 +05:30
Jissin Mathew cb3bed4050 Implement Complete Payments
<UserStory> PAY002: Complete Payments </UserStory>

<Changes>
    1. Integrated Controller with PaymentManagementService to support payment completion workflow.
    2. Implemented PaymentManagementService::completePayment with validation for invoice ID, payment mode, and status update.
    3. Enhanced CustomerMenu with helper functions to display pending invoices in tabular format and allow index-based selection.
    4. Added CustomerMenu::selectPaymentMode to capture payment mode choice (OFFLINE/ONLINE).
    5. Updated CustomerMenu::completePayments to handle invoice selection, payment mode input, and trigger payment completion via Controller.
    6. Implemented notification logic to send confirmation to customers upon successful payment.
</Changes>

<Test>

 Acceptance Criteria:
 1. Payment status marked completed.
 2. Confirmation message shown.
 3. Confirmation notification sent.

 Precondition:
  1. Customer is logged into the system.
  2. At least one pending invoice exists for the customer.
  3. Datastore is available for storing invoices and updating payment status.

 Steps:
  1. Navigate to Customer menu and choose "Complete Payments".
    - Verify that the system lists pending invoices with tabular details.
  2. Select an invoice by index.
    - Verify that the chosen invoice is retrieved correctly.
  3. Enter payment mode (OFFLINE/ONLINE).
    - Verify that the selected mode is applied to the invoice.
  4. Confirm payment completion.
    - Verify that the invoice status changes to COMPLETED.
    - Verify that a confirmation message is displayed.
    - Verify that a notification is sent to the customer.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 15:08:25 +05:30
Avinash Rajesh b230e3062c Implement Remove Customer or Technician Functionality
<UserStory> ADM002: Remove Technician or Customer </UserStory>

<Changes>
    1. Integrated UserManagementService and ServiceManagementService into Controller for user removal operations.
    2. Added Controller::removeUser to validate user existence, cancel related service bookings and technician jobs, and mark user inactive.
    3. Updated JobCard and ServiceBooking models to use util::ServiceJobStatus consistently and store technician references as User* instead of strings.
    4. Extended util::ServiceJobStatus enum with PENDING and CANCELLED states, including string conversion support.
    5. Implemented ServiceManagementService methods to cancel customer service bookings and technician jobs, with inventory restocking and notifications.
    6. Enhanced AdminMenu::removeUser to list active users, validate index input, confirm deletion, and invoke Controller::removeUser.
    7. Added helper functions in AdminMenu to filter active users and display them with formatted output including user type.
</Changes>

<Test>

  Precondition:
  1. Admin is logged into the system.
  2. Technician accounts exist in the system.
  3. Technician has active job assignments.

  Steps:
  1. Navigate to Admin Menu and select "Remove User".
  2. System displays list of active users with IDs, usernames, and user types.
    - Verify that inactive users are excluded from the list.
  3. Admin selects technician ID for removal.
    - Verify that system confirms deletion before proceeding.
  4. Technician is removed from job assignment list.
    - Verify that associated jobs are cancelled, inventory is restocked, and notifications are sent.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:07:25 +05:30
Avinash Rajesh 2bdf0eb741 Implement Add Technician Functionality
<UserStory> ADM001: Add Technician </UserStory>

<Changes>
    1. Added UserManagementService integration in Controller to support technician account creation.
    2. Updated Controller::createTechnician method to call createUser with util::UserType::TECHNICIAN.
    3. Renamed parameter from 'phone' to 'phoneNumber' for clarity and consistency.
    4. Enhanced AdminMenu::addTechnician with input validation for password, email, and phone number.
    5. Added success and error handling messages in AdminMenu for technician creation workflow.
</Changes>

<Test>

  Precondition:
  1. Admin is logged into the system.
  2. UserManagementService is available and connected.
  3. No existing technician account with the same username/email.

  Steps:
  1. Navigate to Admin Menu and select "Add Technician".
  2. Enter technician details (username, password, email, phone number).
    - Verify that invalid password/email/phone inputs are rejected with error messages.
  3. Enter valid technician details.
    - Verify that uniqueness is checked and duplicate accounts are not created.
  4. Submit valid details.
    - Verify that technician account is created successfully and confirmation message is displayed.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:06:32 +05:30
Avinash Rajesh ef41fec208 Implement Check Availability Status Functionality
<UserStory> INV004: Check Availability Status </UserStory>

<Changes>
    1. Updated Controller to delegate getInventoryItem calls to InventoryManagementService.
    2. Implemented InventoryManagementService::getInventoryItem to fetch items from datastore by ID.
    3. Enhanced AdminMenu with checkStockAvailability function:
       - Accepts part ID as input.
       - Retrieves item details from Controller.
       - Displays item information (ID, part name, quantity) if found and active.
       - Handles inactive or missing items gracefully.
</Changes>

<Test>

  Precondition:
  1. Admin user is logged into the system.
  2. Inventory contains multiple items with unique IDs.
  3. DataStore is initialized and accessible.

  Steps:
  1. Navigate to Admin Menu and select "Check Stock Availability".
    - Verify that the system prompts for an Item ID.
  2. Enter a valid Item ID for an active item.
    - Verify that the system displays the item’s details including current quantity.
  3. Enter an Item ID that does not exist.
    - Verify that the system displays “Item not found”.
  4. Enter an Item ID for an inactive item.
    - Verify that the system does not display details and indicates the item is inactive.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:04:37 +05:30
Avinash Rajesh 3594fa4f26 Implement Remove Stock Functionality
<UserStory> INV003: Remove Stock </UserStory>

<Changes>
    1. Integrated InventoryManagementService into Controller to handle removal of inventory items.
    2. Implemented InventoryManagementService::removeInventoryItem to mark items as INACTIVE in the datastore.
    3. Enhanced AdminMenu with removeInventoryItem workflow:
       - Displays inventory list with index, ID, part name, quantity, and price.
       - Allows admin to select item by index for removal.
       - Provides confirmation message after successful deletion.
    4. Added static helper function displayInventoryWithItems in AdminMenu for modularized inventory display.
</Changes>

<Test>

  Precondition:
  1. Admin user is logged into the system.
  2. Inventory contains multiple items with unique IDs.
  3. DataStore is initialized and accessible.

  Steps:
  1. Navigate to Admin Menu and select "Remove Inventory Item".
    - Verify that the system displays all inventory items with ID, part name, quantity, and price.
  2. Select an item by entering its index.
    - Verify that the system removes the item and displays a confirmation message.
  3. Attempt to remove an item with an invalid index.
    - Verify that the system rejects the input and shows an error message.
  4. Navigate to "View Stock Levels".
    - Verify that the removed item no longer appears in the inventory list.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:03:03 +05:30
Jissin Mathew 8162a2fe3d Implement Update Service Status
<UserStory> SER005: Update Service Status </UserStory>

<Changes>
    1. Integrated Controller with ServiceManagementService to support job completion workflow.
    2. Implemented ServiceManagementService::completeJob with validation for technician assignment, job existence, and status transition.
    3. Enhanced TechnicianMenu with job selection helper to display assigned jobs, allow index-based selection, and handle invalid choices.
    4. Updated TechnicianMenu::completeJob to mark job as completed via Controller and provide user feedback.
    5. Added logic to check if all jobs in a booking are completed, triggering invoice generation and customer notification.
</Changes>

<Test>

 Acceptance Criteria:
 1. Status updates are visible to customers immediately after technician marks job as completed.

 Precondition:
  1. Technician is logged into the system.
  2. At least one active job card is assigned to the technician.
  3. Datastore contains valid service bookings linked to jobs.

 Steps:
  1. Navigate to Technician menu and choose "Complete Job".
    - Verify that the system lists active jobs with index-based selection.
  2. Select a job card by index.
    - Verify that the job status changes from STARTED to COMPLETED.
  3. Check customer view.
    - Verify that the updated status is reflected in the customer’s booking history.
  4. If all jobs in the booking are completed:
    - Verify that an invoice is generated and a notification is sent to the customer.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 15:02:46 +05:30
Avinash Rajesh 6a8b845efa Implement Add Stock functionality
<UserStory> INV002: Add Stock </UserStory>

<Changes>
    1. Added Controller integration with InventoryManagementService to support adding new inventory items and updating existing stock quantities.
    2. Implemented InventoryManagementService::addInventoryItem to create new items via Factory and insert them into the DataStore.
    3. Implemented InventoryManagementService::addInventoryItemStock to update stock quantities for existing items.
    4. Enhanced AdminMenu with options to add new items or update stock quantities, including input validation and confirmation messages.
    5. Added helper functions in AdminMenu to display inventory items and handle quantity updates interactively.
    6. Included necessary headers (InventoryItem, Factory, iomanip) for new functionality.
</Changes>

<Test>

  Precondition:
  1. Admin user is logged into the system.
  2. Inventory contains existing items with unique IDs.
  3. DataStore is accessible and initialized.

  Steps:
  1. Navigate to Admin Menu and select "Add Inventory Item".
    - Verify that the system prompts for part name, quantity, and price.
  2. Enter details for a new item with a unique part name and ID.
    - Verify that the item is successfully added and a confirmation message is displayed.
  3. Attempt to add an item with a duplicate ID.
    - Verify that the system rejects the duplicate and displays an error message.
  4. Select "Add Quantity" option for an existing item.
    - Verify that the system updates the stock quantity and displays the new total in the confirmation message.
  5. Navigate to "View Stock Levels".
    - Verify that the updated stock quantity is reflected in the inventory list.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 15:00:59 +05:30
Jissin Mathew fc7bb2569b Implement View Service History
<UserStory> SER004: View Service History </UserStory>

<Changes>
    1. Added integration between Controller and ServiceManagementService to fetch service bookings by customer ID.
    2. Enhanced ServiceBooking model to store technician as a User* instead of a string for richer details.
    3. Implemented Controller::getServiceBookingsByUser to return a read-only map of bookings for safe access.
    4. Updated CustomerMenu::viewServiceHistory to display bookings in tabular format with aligned columns.
    5. Added condition check to show technician name if assigned, otherwise display "Not Assigned".
    6. Included booking status and discount percentage in the service history output.
</Changes>

<Test>

 Acceptance Criteria:
 1. System should fetch real-time status.
 2. Status should update automatically when technician changes it.
 3. Customer should be able to view history.

  Precondition:
  1. Customer is logged into the console application.
  2. At least one active service booking exists for the customer.
  3. Technician has permission to update booking status.

  Steps:
  1. Navigate to Customer menu and choose "View Service History".
    - Verify that the console displays current booking status along with technician assignment.
  2. Technician updates the status of a booking.
    - Verify that the console view reflects the updated status automatically.
  3. Customer views service history again.
    - Verify that the history shows the latest status changes.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 14:59:18 +05:30
Avinash Rajesh 9f882610b3 Implement View Stock Level Functionality
<UserStory> INV001: View Stock Level </UserStory>

<Changes>
    1. Integrated InventoryManagementService into Controller to provide read-only access to inventory items.
    2. Added implementation for InventoryManagementService::getInventoryItems to fetch data from DataStore.
    3. Enhanced AdminMenu with viewStockLevels functionality to display inventory details (ID, part name, quantity, price).
    4. Updated NotificationManagementService interface to provide concrete implementations for sendNotification, attach, detach, and notify methods.
    5. Included necessary headers (InventoryItem, InventoryManagementService, iomanip) for new functionality.
</Changes>

<Test>

  Precondition:
  1. Admin user is logged into the system.
  2. Inventory contains multiple items with varying stock levels.
  3. Notification service is active and users are registered.

  Steps:
  1. Navigate to Admin Menu and select "View Stock Levels".
    - Verify that the system displays all inventory items with ID, part name, quantity, and price.
  2. Check items with sufficient stock.
    - Verify that they are displayed normally without highlighting.
  3. Check items with low stock threshold.
    - Verify that these items are highlighted to indicate low availability.
  4. Trigger a notification for a low-stock item.
    - Verify that the notification is sent to registered users successfully.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 14:57:16 +05:30
Jissin Mathew 70e1ef66d4 Implement Remove Service for admin
<UserStory> SER003: Remove Service </UserStory>

<Changes>
    1. Added integration between Controller and ServiceManagementService to support service removal.
    2. Implemented ServiceManagementService::removeService with validation for service existence and marking as INACTIVE.
    3. Enhanced Controller::getServices to return a read-only map of services for safe UI access.
    4. Added AdminMenu::selectServicesToRemove helper to list active services in tabular format and capture user choice.
    5. Updated AdminMenu::removeService to prompt for service selection, delegate removal to Controller, and display success/failure messages.
</Changes>

<Test>

 Acceptance Criteria:
 1. Admin selects service ID.
 2. System confirms deletion.
 3. Service removed from customer menu.

  Precondition:
  1. Admin is logged into the system.
  2. At least one active service exists in the datastore.
  3. Customer menu displays available services.

  Steps:
  1. Navigate to Admin menu and choose "Remove Service".
    - Verify that the system lists active services in tabular format.
  2. Select a service ID from the list.
    - Verify that the system confirms deletion.
  3. Check customer menu.
    - Verify that the removed service no longer appears.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 14:54:33 +05:30
Jissin Mathew e7f1b51d05 Implement Create Service for admin
<UserStory> SER002: Create Service </UserStory>

<Changes>
    1. Added integration between Controller and ServiceManagementService to support service creation.
    2. Implemented ServiceManagementService::createService with validation for duplicate service IDs and insertion into datastore.
    3. Enhanced AdminMenu with selectInventoryItems helper to display inventory in tabular format, allow selection, and handle exit condition.
    4. Updated AdminMenu::createService to prompt for service name, allow inventory selection, capture labour cost, and create service via Controller.
</Changes>

<Test>

 Acceptance Criteria:
 1. Admin enters new service name.
 2. Admin selects required parts for the services.
 3. Service created and visible to customers.

  Precondition:
  1. Admin is logged into the system.
  2. Inventory contains at least one active item.
  3. Datastore is available for storing services.

  Steps:
  1. Navigate to Admin menu and choose "Create Service".
    - Verify that the system prompts for service name.
  2. Select inventory items from the tabular list.
    - Verify that inactive items are skipped and active items can be added.
  3. Enter labour cost and confirm creation.
    - Verify that the service is created successfully and stored in datastore.
  4. Check customer view.
    - Verify that the newly created service is visible to customers.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 14:51:59 +05:30
Jissin Sam Mathew 9b7d9cf7c1 Implement Assign Job to Technician functionality
<UserStory> SER001: Assign job to technician </UserStory>

<Changes>
    1. Added ServiceManagementService logic to retrieve service bookings and create job cards for assigned technicians.
    2. Added UserManagementService support to retrieve technicians by user type and fetch technician details by ID.
    3. Connected Controller methods with ServiceManagementService and UserManagementService for service booking retrieval, technician listing, and job card creation.
    4. Updated JobCard model to use util::ServiceJobStatus consistently and simplified constructor initialization for assigned and completion timestamps.
    5. Added PENDING status in ServiceJobStatus enum for identifying unassigned service bookings.
    6. Implemented AdminMenu job assignment flow to list pending service bookings, display available technicians, allow technician selection, and assign jobs for services in the booking.
    7. Added notification trigger during job card creation for assigned technicians.
</Changes>

<Test>

Job assignment functionality validation

Precondition:
1. System is running.
2. Pending service bookings are available in the system.
3. Technician users are available in the system.
4. Admin user is logged in and admin menu is active.

Steps:
1. Launch the application and log in as an admin.
2. Select the Assign Job option from the admin menu.
3. View the list of available pending service bookings.
   - Verify that pending bookings are displayed.
4. Select a valid service booking.
5. View the list of available technicians.
   - Verify that technicians are listed for selection.
6. Select a technician to assign the job.
   - Verify that job cards are created for services in the booking.
   - Verify that assigned jobs are visible in the technician’s menu.
   - Verify that a confirmation message is shown.
   - Verify that a confirmation notification is sent to the assigned technician.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 14:50:43 +05:30
Avinash Rajesh a6e19017ca Implement Create Combo Package Functionality
<UserStory> ADM006:Create Combo Package </UserStory>

<Changes>
    1. Added ServiceManagementService::createComboPackage to validate package name, included services, and discount percentage before creation.
    2. Integrated Controller::createComboPackage to delegate combo package creation to ServiceManagementService.
    3. Enhanced AdminMenu::createComboPackages to allow admin input for package name, service selection, and discount percentage.
    4. Implemented service validation to ensure only active services are selectable and that duplicate combos are prevented.
    5. Added formatted output for service listing with cost calculation and confirmation messages upon successful package creation.
</Changes>

<Test>

  Precondition:
  1. Admin is logged into the system.
  2. At least two active services exist in the system.
  3. ServiceManagementService is connected to DataStore for services and combo packages.

  Steps:
  1. Navigate to Admin Menu and select "Create Combo Package".
  2. Enter package name, select two active services, and provide discount percentage.
    - Verify that system validates service IDs and ensures discount is between 0 and 100.
  3. Attempt to create a package with invalid service IDs or duplicate services.
    - Verify that system rejects with appropriate error messages.
  4. Enter valid package details.
    - Verify that combo package is saved successfully and visible to customers.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 13:08:24 +05:30
Avinash Rajesh ab6eed5ee6 Implement Remove Combo Package for admin
<UserStory> SER003: Remove Combo Package </UserStory>

<Changes>

Added integration between Controller and ServiceManagementService to support combo package removal.

Implemented ServiceManagementService::removeComboPackage with validation for package ID and marking state as INACTIVE.

Enhanced AdminMenu with displayComboPackagesWithIndex helper to show packages in tabular format with index.

Updated AdminMenu::selectComboPackage to allow selection of active packages only and return selected package ID.

Updated AdminMenu::removeComboPackage to prompt for selection, confirm removal, and provide success/failure feedback.
</Changes>

<Test>

Acceptance Criteria:

Admin selects package ID.

System confirms deletion.

Package removed from customer menu.

Precondition:

Admin is logged into the system.

At least one active combo package exists.

Datastore is available for storing combo packages.

Steps:

Navigate to Admin menu and choose "Remove Combo Package".

Verify that the system displays available active packages in tabular format with index.

Select a package ID from the list.

Verify that inactive packages are skipped and only active ones are selectable.

Confirm removal.

Verify that the package is marked INACTIVE and removed from customer menu.

Check customer view.

Verify that the removed package is no longer visible to customers.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 12:44:00 +05:30
joelthomastrenser 454af1b4ef Implement Admin and Technician Menus
Changes:
  - Added Admin Menu display with menu options
  - Added Technician Menu display with menu options
  - Added menu choice handling using switch case
  - Connected menu options to corresponding functions
  - Added invalid choice message
  - Added logout handling
  - Added missing function declarations in TechnicianMenu header
2026-05-21 10:46:23 +05:30
Avinash Rajesh df769a7528 Implement Logout functionality
<UserStory> ADM004: Logout </UserStory>

<Changes>
    1. Added AuthenticationManagementService::logout to clear authenticated user session.
    2. Integrated logout handling in Controller::logout to delegate session termination.
    3. Updated AdminMenu::logout and TechnicianMenu::logout to call Controller::logout for consistent session management.
    4. Extended TechnicianMenu.h with logout method declaration.
    5. Ensured session termination returns control to main menu after logout.
</Changes>

<Test>

  Precondition:
  1. User is logged into the system (Admin or Technician).
  2. AuthenticationManagementService maintains active session.
  3. Controller is connected to AuthenticationManagementService.

  Steps:
  1. Navigate to Admin or Technician Menu.
  2. Select "Logout" option.
    - Verify that AuthenticationManagementService::logout clears authenticated user.
  3. Session is terminated.
    - Verify that system confirms logout and invalidates session.
  4. Console returns to main menu.
    - Verify that user is redirected to main menu and must log in again to continue.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-21 10:39:53 +05:30
26 changed files with 2718 additions and 258 deletions
@@ -6,10 +6,16 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept> #include "ComboPackage.h"
#include "Controller.h" #include "Controller.h"
#include "Enums.h" #include "Enums.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "User.h" #include "User.h"
#include <stdexcept>
/* /*
Function: login Function: login
@@ -72,8 +78,19 @@ const User* Controller::getAuthenticatedUser()
return m_authenticationManagementService.getAuthenticatedUser(); return m_authenticationManagementService.getAuthenticatedUser();
} }
void Controller::createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone) /*
Function: createTechnician
Description: Creates a new technician account with provided details by
delegating to the user management service.
Parameter: const std::string& username - technician's username
const std::string& password - technician's password
const std::string& email - technician's email address
const std::string& phoneNumber - technician's phone number
Return type: void
*/
void Controller::createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phoneNumber)
{ {
m_userManagementService.createUser(username, name, password, email, phoneNumber, util::UserType::TECHNICIAN);
} }
/* /*
@@ -93,14 +110,45 @@ void Controller::updateUserDetails(const std::string& email, const std::string&
m_userManagementService.updateUserDetails(authenticatedUser->getId(), email, phone); 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, const Service*> Controller::getServices()
{ {
return util::Map<std::string, const Service*>(); 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;
} }
/*
Function: getComboPackages
Description: Retrieves all available combo packages from the service
management service and constructs a read-only map.
Parameter: None
Return type: util::Map<std::string, const ComboPackage*>
*/
util::Map<std::string, const ComboPackage*> Controller::getComboPackages() util::Map<std::string, const ComboPackage*> Controller::getComboPackages()
{ {
return util::Map<std::string, const ComboPackage*>(); util::Map<std::string, ComboPackage*> currentAvailableComboPackages = m_serviceManagementService.getComboPackages();
util::Map<std::string, const ComboPackage*> readOnlyComboPackages;
for (int iterator = 0; iterator < currentAvailableComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentAvailableComboPackages.getValueAt(iterator);
if (currentComboPackage)
{
readOnlyComboPackages.insert(currentComboPackage->getId(), currentComboPackage);
}
}
return readOnlyComboPackages;
} }
/* /*
@@ -131,84 +179,303 @@ void Controller::purchaseComboPackage(const std::string& comboPackageID, const s
m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel); m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel);
} }
/*
Function: getInventoryItems
Description: Retrieves all inventory items from the inventory management service
and constructs a read-only map for external use.
Parameter: None
Return type: util::Map<std::string, const InventoryItem*>
*/
util::Map<std::string, const InventoryItem*> Controller::getInventoryItems() util::Map<std::string, const InventoryItem*> Controller::getInventoryItems()
{ {
return util::Map<std::string, const InventoryItem*>(); auto inventoryItems = m_inventoryManagementService.getInventoryItems();
util::Map<std::string, const InventoryItem*> readOnlyInventoryItems;
int inventoryItemsMapSize = inventoryItems.getSize();
for (int index = 0; index < inventoryItemsMapSize; index++)
{
readOnlyInventoryItems.insert(inventoryItems.getKeyAt(index), inventoryItems.getValueAt(index));
}
return readOnlyInventoryItems;
} }
/*
Function: getInventoryItem
Description: Retrieves a specific inventory item by its ID from the inventory management service.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: const InventoryItem*
*/
const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID) const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID)
{ {
return nullptr; return m_inventoryManagementService.getInventoryItem(inventoryItemID);
} }
/*
Function: addInventoryItem
Description: Adds a new inventory item with specified details to the inventory management service.
Parameter: const std::string& partName - name of the part
int quantity - quantity of the part
double price - price of the part
Return type: void
*/
void Controller::addInventoryItem(const std::string& partName, int quantity, double price) void Controller::addInventoryItem(const std::string& partName, int quantity, double price)
{ {
m_inventoryManagementService.addInventoryItem(partName, quantity, price);
} }
/*
Function: removeInventoryItem
Description: Removes an inventory item from the inventory management service by its ID.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: void
*/
void Controller::removeInventoryItem(const std::string& inventoryItemID) void Controller::removeInventoryItem(const std::string& inventoryItemID)
{ {
m_inventoryManagementService.removeInventoryItem(inventoryItemID);
} }
/*
Function: addInventoryItemStock
Description: Adds stock to an existing inventory item in the inventory management service.
Parameter: const std::string& selectedItemId - ID of the inventory item
int quantity - quantity to add
Return type: void
*/
void Controller::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{
m_inventoryManagementService.addInventoryItemStock(selectedItemId, quantity);
}
/*
Function: getServiceBookings
Description: Retrieves all service bookings in read-only form.
Parameters:
- None
Returns:
- util::Map<std::string, const ServiceBooking*> containing service bookings
*/
util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings() util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings()
{ {
return util::Map<std::string, const ServiceBooking*>(); 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;
} }
/*
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*> Controller::getServiceBookingsByUser(const std::string userID)
{ {
return util::Map<std::string, const ServiceBooking*>(); 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;
} }
/*
Function: getUsers
Description: Retrieves all users from the user management service and
constructs a read-only map.
Parameter: None
Return type: util::Map<std::string, const User*>
*/
util::Map<std::string, const User*> Controller::getUsers() util::Map<std::string, const User*> Controller::getUsers()
{ {
return util::Map<std::string, const User*>(); auto listOfUsers = m_userManagementService.getUsers();
util::Map<std::string, const User*> readOnlyUserList;
for (int iterator = 0; iterator < listOfUsers.getSize(); iterator++)
{
readOnlyUserList.insert(listOfUsers.getKeyAt(iterator), listOfUsers.getValueAt(iterator));
}
return readOnlyUserList;
} }
/*
Function: getUsers
Description: Retrieves users filtered by user type.
Parameters:
- userType: util::UserType, type of user (CUSTOMER, TECHNICIAN, ADMIN)
Returns:
- util::Map<std::string, const User*> containing users of the specified type
*/
util::Map<std::string, const User*> Controller::getUsers(util::UserType userType) util::Map<std::string, const User*> Controller::getUsers(util::UserType userType)
{ {
return util::Map<std::string, const User*>(); 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;
} }
/*
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) 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) 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) 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() util::Map<std::string, const JobCard*> Controller::getJobCardsByUser()
{ {
return util::Map<std::string, const JobCard*>(); 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;
} }
/*
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) void Controller::completeJob(const std::string& jobID)
{ {
m_serviceManagementService.completeJob(jobID);
} }
/*
Function: removeUser
Description: Removes a user by ID. Cancels associated service bookings
and technician jobs before removing the user from the system.
Parameter: const std::string& userID - ID of the user to remove
Return type: void
*/
void Controller::removeUser(const std::string& userID) void Controller::removeUser(const std::string& userID)
{ {
User* user = m_userManagementService.getUser(userID);
if (!user)
{
throw std::runtime_error("Error User not Found.\n");
}
m_serviceManagementService.cancelCustomerServiceBookings(userID);
m_serviceManagementService.cancelTechnicianJobs(userID);
m_userManagementService.removeUser(userID);
} }
/*
Function: createComboPackage
Description: Creates a new combo package with specified services and discount
percentage by delegating to the service management service.
Parameter: const std::string& name - name of the combo package
const util::Vector<std::string>& serviceIDs - list of service IDs
double discountPercentage - discount percentage for the package
Return type: void
*/
void Controller::createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage) void Controller::createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage)
{ {
m_serviceManagementService.createComboPackage(name, serviceIDs, discountPercentage);
} }
/*
Function: removeComboPackage
Description: Removes a combo package by ID by delegating to the service
management service.
Parameter: const std::string& comboPackageID - ID of the combo package
Return type: void
*/
void Controller::removeComboPackage(const std::string& comboPackageID) void Controller::removeComboPackage(const std::string& comboPackageID)
{ {
m_serviceManagementService.removeComboPackage(comboPackageID);
} }
/*
Function: getInvoicesByUser
Description: Retrieves all invoices associated with the currently authenticated user.
Converts them into a read-only map before returning.
Parameters:
- None
Returns:
- util::Map<std::string, const Invoice*> containing the users invoices
*/
util::Map<std::string, const Invoice*> Controller::getInvoicesByUser() util::Map<std::string, const Invoice*> Controller::getInvoicesByUser()
{ {
return util::Map<std::string, const Invoice*>(); User* currentUser = m_authenticationManagementService.getAuthenticatedUser();
util::Map<std::string, Invoice*> currentUserInvoices = m_paymentManagementService.getInvoices(currentUser->getId());
util::Map<std::string, const Invoice*> userInvoicesReadOnly;
for (int iterator = 0; iterator < currentUserInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentUserInvoices.getValueAt(iterator);
userInvoicesReadOnly.insert(currentInvoice->getId(), currentInvoice);
}
return userInvoicesReadOnly;
} }
/*
Function: completePayment
Description: Completes payment for a specific invoice using the given payment mode.
Parameters:
- invoiceID: std::string, ID of the invoice to be paid
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
*/
void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode) void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{ {
m_paymentManagementService.completePayment(invoiceID, paymentMode);
} }
/* /*
@@ -1,11 +1,12 @@
/* /*
File: Controller.h File: Controller.h
Description: Header file declaring the Controller class, which coordinates Description: Header file declaring the Controller class, which manages
authentication, user management, service management, inventory, user authentication, inventory, services, bookings, job cards,
and notifications across the Vehicle Service System. invoices, and notifications in the system.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
@@ -15,10 +16,6 @@ Date:19-May-2026
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "InventoryManagementService.h"
#include "UserManagementService.h"
#include "ServiceManagementService.h"
#include "PaymentManagementService.h"
class Service; class Service;
class ComboPackage; class ComboPackage;
@@ -52,6 +49,7 @@ public:
util::Map<std::string, const InventoryItem*> getInventoryItems(); util::Map<std::string, const InventoryItem*> getInventoryItems();
const InventoryItem* getInventoryItem(const std::string& inventoryItemID); const InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price); void addInventoryItem(const std::string& partName, int quantity, double price);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void removeInventoryItem(const std::string& inventoryItemID); void removeInventoryItem(const std::string& inventoryItemID);
util::Map<std::string, const ServiceBooking*> getServiceBookings(); util::Map<std::string, const ServiceBooking*> getServiceBookings();
util::Map<std::string, const ServiceBooking*> getServiceBookingsByUser(const std::string userID); util::Map<std::string, const ServiceBooking*> getServiceBookingsByUser(const std::string userID);
@@ -58,8 +58,8 @@ Invoice::Invoice(
const std::string& bookingId, const std::string& bookingId,
ServiceBooking* booking, ServiceBooking* booking,
const util::Timestamp& invoiceDate, const util::Timestamp& invoiceDate,
double laborCost, const util::Map<std::string, double laborCost,
InventoryItem*>& parts, const util::Map<std::string, InventoryItem*>& parts,
double partsCost, double partsCost,
double discountPercentage, double discountPercentage,
double totalAmount, double totalAmount,
@@ -87,7 +87,6 @@ Invoice::Invoice(
m_partIDs.push_back(partPointers[index]->getId()); m_partIDs.push_back(partPointers[index]->getId());
} }
} }
Invoice::Invoice( Invoice::Invoice(
const std::string& id, const std::string& id,
const std::string& bookingId, const std::string& bookingId,
@@ -40,8 +40,8 @@ public:
const std::string& bookingId, const std::string& bookingId,
ServiceBooking* booking, ServiceBooking* booking,
const util::Timestamp& invoiceDate, const util::Timestamp& invoiceDate,
double laborCost, const util::Map<std::string, double laborCost,
InventoryItem*>& parts, const util::Map<std::string,InventoryItem*>& parts,
double partsCost, double partsCost,
double discountPercentage, double discountPercentage,
double totalAmount, double totalAmount,
@@ -1,8 +1,8 @@
/* /*
File: JobCard.cpp File: JobCard.cpp
Description: Implements the JobCard class which represents a technicians job assignment in the Vehicle Service Management System. Description: Implementation file containing the method definitions of the
Provides constructors, accessors, and mutators for job details such as ID, booking, service, technician, JobCard class, including constructors, getters, and setters
assigned date, completion date, and job status. for job card attributes.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
@@ -18,12 +18,10 @@ int JobCard::m_uid = 0;
/* /*
Function: JobCard Function: JobCard
Description: Default constructor that initializes a new job card with a unique ID, Description: Default constructor that initializes a new job card with
null booking, null service, null technician, and default job status. a unique ID and default values.
Parameters: Parameter: None
- None Return type: Constructor
Returns:
- A new JobCard object.
*/ */
JobCard::JobCard() JobCard::JobCard()
: m_id("JC" + std::to_string(++m_uid)), : m_id("JC" + std::to_string(++m_uid)),
@@ -1,15 +1,16 @@
/* /*
File: JobCard.h File: JobCard.h
Description: Declares the JobCard class which represents a technicians job assignment in the Vehicle Service Management System. Description: Header file declaring the JobCard class, which represents
Each job card includes booking details, associated service, technician information, assigned and completion dates, and job status. a service job card containing booking, service, technician,
and status details.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Timestamp.h"
#include "Enums.h" #include "Enums.h"
#include "Timestamp.h"
class ServiceBooking; class ServiceBooking;
class Service; class Service;
@@ -29,7 +30,6 @@ private:
util::Timestamp m_assignedDate; util::Timestamp m_assignedDate;
util::ServiceJobStatus m_status; util::ServiceJobStatus m_status;
util::Timestamp m_completionDate; util::Timestamp m_completionDate;
public: public:
JobCard(); JobCard();
JobCard(const std::string& bookingId, JobCard(const std::string& bookingId,
@@ -41,8 +41,6 @@ Parameters:
- vehicleNumber: Vehicle registration number. - vehicleNumber: Vehicle registration number.
- vehicleBrand: Brand of the vehicle. - vehicleBrand: Brand of the vehicle.
- vehicleModel: Model of the vehicle. - vehicleModel: Model of the vehicle.
- assignedTechnicianId: ID of the assigned technician.
- assignedTechnician: Name of the assigned technician.
- discountPercentage: Discount applied to the booking. - discountPercentage: Discount applied to the booking.
Returns: Returns:
- A new ServiceBooking object. - A new ServiceBooking object.
@@ -161,6 +159,12 @@ const util::Vector<std::string>& ServiceBooking::getServiceIDs() const
return m_serviceIDs; return m_serviceIDs;
} }
/*
Function: getServices
Description: Retrieves the services associated with the booking.
Parameter: None
Return type: const util::Map<std::string, Service*>&
*/
/* /*
Function: getServices Function: getServices
Description: Retrieves the services associated with the booking. Description: Retrieves the services associated with the booking.
@@ -1,11 +1,12 @@
/* /*
File: AuthenticationManagementService.cpp File: AuthenticationManagementService.cpp
Description: Implementation file containing the method definitions of the Description: Implementation file containing the method definitions of the
AuthenticationManagementService class, including login, logout, AuthenticationManagementService class, including logout and
password change, and retrieval of the authenticated user. password change logic.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept> #include <stdexcept>
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "User.h" #include "User.h"
@@ -6,6 +6,7 @@ Description: Header file declaring the AuthenticationManagementService class, wh
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "DataStore.h" #include "DataStore.h"
@@ -20,86 +20,9 @@ Date: 22-May-2026
#include "Utility.h" #include "Utility.h"
#include "Vector.h" #include "Vector.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
/*
Function: attach
Description: Adds a user to the observer list for receiving inventory notifications.
Parameters:
- user: User*, pointer to the user to be attached as an observer
Returns:
- None
*/
void InventoryManagementService::attach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) == -1)
{
m_observers[userID] = user;
}
}
}
/*
Function: detach
Description: Removes a user from the observer list so they no longer receive inventory notifications.
Parameters:
- user: User*, pointer to the user to be detached from the observer list
Returns:
- None
*/
void InventoryManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
/*
Function: sendNotification
Description: Sends a notification to a user if they are subscribed as an observer.
Parameters:
- user: User*, pointer to the user receiving the notification
- title: std::string, title of the notification
- message: std::string, body/content of the notification
Returns:
- None
Throws:
- std::runtime_error if notification creation fails
*/
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
"InventoryManagementService: " + title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
/* /*
Function: sendLowStockAlertsToAdmins (static helper) Function: sendLowStockAlertsToAdmins (static helper)
Description: Sends low stock alert notifications to all admin users for a given inventory item. Description: Sends low stock alert notifications to all admin users for a given inventory item.
@@ -136,6 +59,10 @@ Returns:
void InventoryManagementService::sendLowStockAlerts() void InventoryManagementService::sendLowStockAlerts()
{ {
auto& inventoryItems = m_dataStore.getInventoryItems(); auto& inventoryItems = m_dataStore.getInventoryItems();
if (inventoryItems.isEmpty())
{
return;
}
int inventoryItemsSize = inventoryItems.getSize(); int inventoryItemsSize = inventoryItems.getSize();
auto& usersMap = m_dataStore.getUsers(); auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize(); int usersMapSize = usersMap.getSize();
@@ -251,3 +178,164 @@ void InventoryManagementService::saveObservers()
{ {
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
} }
/*
Function: addInventoryItem
Description: Creates a new inventory item using the Factory and inserts it
into the DataStore.
Parameter: const std::string& partName - name of the part
int quantity - initial quantity of the part
double price - price of the part
Return type: void
*/
void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price)
{
InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price);
m_dataStore.getInventoryItems().insert(newItem->getId(), newItem);
}
/*
Function: addInventoryItemStock
Description: Increases the stock quantity of an existing inventory item.
Parameter: const std::string& selectedItemId - ID of the inventory item
int quantity - quantity to add
Return type: void
*/
void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{
int index = m_dataStore.getInventoryItems().find(selectedItemId);
if (index != -1)
{
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
if (item != nullptr)
{
int totalQuantity = item->getQuantity() + quantity;
item->setQuantity(totalQuantity);
}
}
}
/*
Function: getInventoryItems
Description: Retrieves all inventory items stored in the DataStore.
Parameter: None
Return type: util::Map<std::string, InventoryItem*>
*/
util::Map<std::string, InventoryItem*> InventoryManagementService::getInventoryItems()
{
return m_dataStore.getInventoryItems();
}
/*
Function: removeInventoryItem
Description: Marks an inventory item as inactive instead of deleting it.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: void
*/
void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID)
{
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
if (index != -1)
{
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
if (item != nullptr)
{
item->setState(util::State::INACTIVE);
}
}
}
/*
Function: getInventoryItem
Description: Retrieves a specific inventory item by its ID from the DataStore.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: InventoryItem*
*/
InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID)
{
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
if (index != -1)
{
return m_dataStore.getInventoryItems().getValueAt(index);
}
return nullptr;
}
/*
Function: attach
Description: Adds a user to the observer list for receiving inventory notifications.
Parameters:
- user: User*, pointer to the user to be attached as an observer
Returns:
- None
*/
void InventoryManagementService::attach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) == -1)
{
m_observers[userID] = user;
}
}
}
/*
Function: detach
Description: Removes a user from the observer list so they no longer receive inventory notifications.
Parameters:
- user: User*, pointer to the user to be detached from the observer list
Returns:
- None
*/
void InventoryManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
/*
Function: sendNotification
Description: Sends a notification to a user if they are subscribed as an observer.
Parameters:
- user: User*, pointer to the user receiving the notification
- title: std::string, title of the notification
- message: std::string, body/content of the notification
Returns:
- None
Throws:
- std::runtime_error if notification creation fails
*/
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
"InventoryManagementService: " + title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
@@ -1,7 +1,8 @@
/* /*
File: InventoryManagementService.h File: InventoryManagementService.h
Description: Declares the InventoryManagementService class which manages inventory operations in the Vehicle Service Management System. Description: Header file declaring the InventoryManagementService class,
Provides functionality to retrieve, add, and remove inventory items, send low stock alerts, and handle notifications using the Observer pattern. which manages inventory items, stock updates, and notifications
related to low stock alerts. Inherits from NotificationManagementService.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
@@ -27,6 +28,7 @@ public:
InventoryItem* getInventoryItem(const std::string& inventoryItemID); InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price); void addInventoryItem(const std::string& partName, int quantity, double price);
void removeInventoryItem(const std::string& inventoryItemID); void removeInventoryItem(const std::string& inventoryItemID);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void sendLowStockAlerts(); void sendLowStockAlerts();
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
@@ -12,8 +12,11 @@ Date: 20-May-2026
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h" #include "FileManager.h"
#include "InventoryItem.h"
#include "Invoice.h" #include "Invoice.h"
#include "JobCard.h"
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
#include "Service.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
@@ -253,3 +256,131 @@ void PaymentManagementService::saveObservers()
{ {
util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this);
} }
/*
Function: createInventoryItemsMap (static helper)
Description: Builds a map of inventory items required for a given service and adds them to the bookings inventory map.
Parameters:
- completeInventoryItemMapOfBooking: util::Map<std::string, InventoryItem*>&, map to store inventory items for the booking
- currentService: const Service*, pointer to the current service
Returns:
- void
*/
static void createInventoryItemsMap(util::Map<std::string, InventoryItem*>& completeInventoryItemMapOfBooking, const Service* currentService)
{
auto& currentRequiredInventoryItems = currentService->getRequiredInventoryItems();
for (int iterator = 0; iterator < currentRequiredInventoryItems.getSize(); iterator++)
{
auto& currentRequiredInventoryItem = currentRequiredInventoryItems.getValueAt(iterator);
completeInventoryItemMapOfBooking.insert(currentRequiredInventoryItem->getId(), currentRequiredInventoryItem);
}
}
/*
Function: generateInvoice
Description: Generates an invoice for a completed service booking.
Validates that all job cards are completed, calculates labor and parts cost, applies discount,
and stores the invoice in the datastore.
Parameters:
- booking: ServiceBooking*, pointer to the service booking
Returns:
- void
Throws:
- std::runtime_error if booking is null or job cards are incomplete
*/
void PaymentManagementService::generateInvoice(ServiceBooking* booking)
{
if (!booking)
{
throw std::runtime_error("Invoice generation failed: booking is null.");
}
double totalLabourCost = 0, totalPartsCost = 0, totalServiceCost = 0;
double discountPercentage = booking->getDiscountPercentage();
std::string bookingID = booking->getId();
util::Map<std::string, Service*> servicesInTheBookedService = booking->getServices();
util::Map<std::string, InventoryItem*> completeInventoryItemMapOfBooking;
util::Map<std::string, JobCard*> currentJobCards = m_dataStore.getJobCards();
for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++)
{
JobCard* currentJobCard = currentJobCards.getValueAt(iterator);
if (currentJobCard->getBookingId() == bookingID && currentJobCard->getStatus() != util::ServiceJobStatus::COMPLETED)
{
throw std::runtime_error("Invoice generation failed: not all job cards are completed for booking '" + bookingID + "'.");
}
}
for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++)
{
Service* currentService = servicesInTheBookedService.getValueAt(iterator);
if (currentService)
{
createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService);
totalLabourCost += currentService->getLaborCost();
totalPartsCost += util::calculatePartsCost(currentService);
}
}
totalServiceCost = totalLabourCost + totalPartsCost;
totalServiceCost -= (totalServiceCost * (discountPercentage / 100));
Invoice* invoice = Factory::getObject<Invoice>(bookingID, booking, util::Timestamp(), totalLabourCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING);
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
currentInvoices.insert(invoice->getId(), invoice);
}
/*
Function: getInvoices
Description: Retrieves all invoices associated with a specific customer.
Parameters:
- customerID: std::string, ID of the customer
Returns:
- util::Map<std::string, Invoice*> containing the customers invoices
*/
util::Map<std::string, Invoice*> PaymentManagementService::getInvoices(const std::string& customerID)
{
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
util::Map<std::string, Invoice*> currentUserInvoices;
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice->getBooking()->getCustomerId() == customerID)
{
currentUserInvoices.insert(currentInvoice->getId(), currentInvoice);
}
}
return currentUserInvoices;
}
/*
Function: completePayment
Description: Completes payment for a specific invoice. Updates payment method, date, and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex != -1)
{
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (invoice && invoice->getStatus() != util::PaymentStatus::COMPLETED)
{
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentMethod(paymentMode);
invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title, message;
title = "Payment successful";
message = "Payment successful for invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
}
}
else
{
throw std::runtime_error("Payment failed: invalid invoice ID.");
}
}
@@ -11,14 +11,21 @@ Date:19-May-2026
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "ComboPackage.h" #include "ComboPackage.h"
#include "Config.h" #include "Config.h"
#include "DataStore.h"
#include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h" #include "FileManager.h"
#include "InventoryItem.h"
#include "JobCard.h" #include "JobCard.h"
#include "NotificationManagementService.h"
#include "PaymentManagementService.h"
#include "Service.h" #include "Service.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Timestamp.h"
#include "User.h" #include "User.h"
#include "UserManagementService.h"
#include "Utility.h" #include "Utility.h"
/* /*
@@ -500,3 +507,546 @@ void ServiceManagementService::saveObservers()
{ {
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
} }
/*
Function: cancelCustomerServiceBookings
Description: Cancels all service bookings associated with a given customer or technician.
Updates booking status, resets customer/technician assignments, sends notifications,
and restocks inventory items.
Parameter: const std::string& userID - ID of the customer or technician
Return type: void
*/
void ServiceManagementService::cancelCustomerServiceBookings(const std::string& userID)
{
const int INCREMENT_VALUE = 1;
auto& users = m_dataStore.getUsers();
int userIndex = users.find(userID);
if (userIndex == -1)
{
throw std::runtime_error("User not found: " + userID);
}
User* user = users.getValueAt(userIndex);
if (user == nullptr)
{
throw std::runtime_error("User not found: " + userID);
}
util::UserType type = user->getUserType();
auto& bookings = DataStore::getInstance().getServiceBookings();
for (int bookingIterator = 0; bookingIterator < bookings.getSize(); bookingIterator++)
{
ServiceBooking* booking = bookings.getValueAt(bookingIterator);
if (booking != nullptr &&
(booking->getCustomerId() == userID || booking->getAssignedTechnicianId() == userID))
{
if (booking->getStatus() == util::ServiceJobStatus::PENDING ||
booking->getStatus() == util::ServiceJobStatus::STARTED)
{
if (type == util::UserType::CUSTOMER)
{
booking->setStatus(util::ServiceJobStatus::CANCELLED);
booking->setCustomer(nullptr);
booking->setCustomerId("");
User* assignedTechnician = booking->getAssignedTechnician();
std::string title = "Customer Service Cancelled";
std::string message = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked.";
sendNotification(assignedTechnician, title, message);
}
else if (type == util::UserType::TECHNICIAN)
{
booking->setStatus(util::ServiceJobStatus::PENDING);
std::string title = "Technician Unavailable";
std::string message = "Your assigned technician is no longer available. Your booking has been reset to pending, and we will reassign a new technician shortly.";
sendNotification(booking->getCustomer(), title, message);
}
booking->setAssignedTechnician(nullptr);
booking->setAssignedTechnicianId("");
const auto& ListOfServices = booking->getServices();
for (int serviceIterator = 0; serviceIterator < ListOfServices.getSize(); serviceIterator++)
{
Service* service = ListOfServices.getValueAt(serviceIterator);
if (service != nullptr)
{
const auto& items = service->getRequiredInventoryItems();
for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++)
{
InventoryItem* item = items.getValueAt(itemIterator);
if (item != nullptr)
{
item->setQuantity(item->getQuantity() + INCREMENT_VALUE);
}
}
}
}
}
}
}
}
/*
Function: cancelTechnicianJobs
Description: Cancels all jobs assigned to a technician. Updates job status, sends notifications,
and restocks inventory items used in the service.
Parameter: const std::string& technicianID - ID of the technician
Return type: void
*/
void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID)
{
const int INCREMENT_VALUE = 1;
auto& jobs = m_dataStore.getJobCards();
for (int jobIterator = 0; jobIterator < jobs.getSize(); jobIterator++)
{
JobCard* job = jobs.getValueAt(jobIterator);
if (job != nullptr && job->getTechnicianId() == technicianID)
{
if (job->getStatus() == util::ServiceJobStatus::PENDING || job->getStatus() == util::ServiceJobStatus::STARTED)
{
job->setStatus(util::ServiceJobStatus::CANCELLED);
std::string title = "Job Cancelled";
std::string message = "The Job has cancelled. Your job card has been cancelled and the inventory has been restocked.";
sendNotification(job->getTechnician(), title, message);
Service* service = job->getService();
if (service != nullptr)
{
const auto& items = service->getRequiredInventoryItems();
for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++)
{
InventoryItem* item = items.getValueAt(itemIterator);
if (item != nullptr)
{
item->setQuantity(item->getQuantity() + INCREMENT_VALUE);
}
}
}
}
}
}
}
/*
Function: createComboPackage
Description: Creates a new combo package with two services and a discount percentage.
Validates service IDs, ensures uniqueness, and inserts the new package into the DataStore.
Parameter: const std::string& packageName - name of the combo package
const util::Vector<std::string>& serviceIDsInNewCombo - list of service IDs
double discountPercentage - discount percentage for the package
Return type: void
*/
void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDsInNewCombo, double discountPercentage)
{
if (packageName.empty())
{
throw std::invalid_argument("The Combo Package Name cannot be empty.\n");
}
if (serviceIDsInNewCombo.getSize() < 2 || serviceIDsInNewCombo.getSize() > 2)
{
throw std::invalid_argument("Combo package must contain only two services.");
}
if (discountPercentage < 0.0 || discountPercentage > 100.0)
{
throw std::invalid_argument("Discount percentage must be between 0 and 100.");
}
auto& servicesMap = m_dataStore.getServices();
for (int index = 0; index < serviceIDsInNewCombo.getSize(); index++)
{
const std::string serviceid = serviceIDsInNewCombo[index];
if (servicesMap.find(serviceid) == -1)
{
throw std::runtime_error("Service ID not found: " + serviceid);
}
}
auto& comboPackageMap = m_dataStore.getComboPackages();
for (int iterator = 0; iterator < comboPackageMap.getSize(); iterator++)
{
ComboPackage* existingCombos = comboPackageMap.getValueAt(iterator);
const util::Map<std::string, Service*>& servicesInsideExistingCombos = existingCombos->getServices();
if (servicesInsideExistingCombos.getSize() == serviceIDsInNewCombo.getSize())
{
bool isIdentical = true;
for (int serviceIterator = 0; serviceIterator < serviceIDsInNewCombo.getSize(); serviceIterator++)
{
const std::string& id = serviceIDsInNewCombo[serviceIterator];
if (servicesInsideExistingCombos.find(id) == -1)
{
isIdentical = false;
break;
}
}
if (isIdentical)
{
throw std::runtime_error("A combo package with the same services already exists.");
}
}
}
util::Map<std::string, Service*> selectedServices;
for (int iteratorOne = 0; iteratorOne < serviceIDsInNewCombo.getSize(); iteratorOne++)
{
const std::string& serviceId = serviceIDsInNewCombo[iteratorOne];
int serviceIndex = servicesMap.find(serviceId);
if (serviceIndex == -1)
{
throw std::runtime_error("Service ID not found: " + serviceId);
}
selectedServices.insert(serviceId, servicesMap.getValueAt(serviceIndex));
}
ComboPackage* newComboPackage = Factory::getObject<ComboPackage>(packageName, discountPercentage, selectedServices);
comboPackageMap.insert(newComboPackage->getId(), newComboPackage);
}
/*
Function: getComboPackages
Description: Retrieves all combo packages stored in the DataStore.
Parameter: None
Return type: util::Map<std::string, ComboPackage*>
*/
util::Map<std::string, ComboPackage*> ServiceManagementService::getComboPackages()
{
return m_dataStore.getComboPackages();
}
/*
Function: removeComboPackage
Description: Removes a combo package by marking it inactive. Throws an exception if the package ID is not found.
Parameter: const std::string& comboPackageID - ID of the combo package
Return type: void
*/
void ServiceManagementService::removeComboPackage(const std::string& comboPackageID)
{
bool removed = false;
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator);
if (currentComboPackage && currentComboPackage->getId() == comboPackageID)
{
currentComboPackage->setState(util::State::INACTIVE);
removed = true;
break;
}
}
if (!removed)
{
throw std::runtime_error("Combo package with ID '" + comboPackageID + "' not found.");
}
}
/*
Function: getServiceBookings
Description: Retrieves all service bookings from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, ServiceBooking*> containing all service bookings
*/
util::Map<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings()
{
return m_dataStore.getServiceBookings();
}
/*
Function: getServiceBooking
Description: Retrieves a specific service booking by its ID.
Parameters:
- serviceID: std::string, ID of the service booking
Returns:
- ServiceBooking*: Pointer to the service booking, or nullptr if not found
*/
ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID)
{
auto currentServiceBookings = getServiceBookings();
for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++)
{
if (currentServiceBookings.getValueAt(iterator)->getId() == serviceID)
{
return currentServiceBookings.getValueAt(iterator);
}
}
return nullptr;
}
/*
Function: createJobCard
Description: Creates a job card for a given service booking, service, and technician.
Validates booking, service, technician, and inventory availability before creation.
Parameters:
- bookingID: std::string, ID of the service booking
- technicianID: std::string, ID of the technician
- serviceID: std::string, ID of the service
Returns:
- void
Throws:
- std::runtime_error if booking, service, technician, or inventory validation fails
*/
void ServiceManagementService::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID)
{
UserManagementService m_userManagementService;
ServiceBooking* currentBooking = getServiceBooking(bookingID);
auto& currentJobCards = m_dataStore.getJobCards();
if (currentBooking == nullptr)
{
throw std::runtime_error("Service Booking not available");
}
auto& currentServices = currentBooking->getServices();
if (currentServices.find(serviceID) == -1)
{
throw std::runtime_error("Invalid service Id");
}
Service* currentService = currentServices.getValueAt(currentServices.find(serviceID));
User* selectedTechnician = m_userManagementService.getUser(technicianID);
if (selectedTechnician == nullptr)
{
throw std::runtime_error("Technician not available");
}
auto& inventoryItems = currentService->getRequiredInventoryItems();
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem && currentInventoryItem->getQuantity() == 0)
{
std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock.";
throw std::runtime_error(errorMessage);
}
}
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem)
{
int currentStockQuantity = currentInventoryItem->getQuantity();
currentInventoryItem->setQuantity(currentStockQuantity - 1);
}
}
currentBooking->setAssignedTechnician(selectedTechnician);
currentBooking->setAssignedTechnicianId(selectedTechnician->getId());
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());
if (jobCard)
{
currentJobCards.insert(jobCard->getId(), jobCard);
sendNotification(selectedTechnician, title, message);
}
else
{
throw std::runtime_error("Failed to create job card.");
}
}
/*
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 = m_dataStore.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: hasCompletedAllJobs (static helper)
Description: Checks if all job cards for a given service booking are completed.
Parameters:
- bookingId: std::string, ID of the service booking
- currentAssignedJobs: util::Map<std::string, JobCard*>&, map of assigned job cards
Returns:
- bool: True if all job cards are completed, False otherwise
*/
static bool hasCompletedAllJobs(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 = hasCompletedAllJobs(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);
}
}
@@ -6,6 +6,7 @@ Description: Header file declaring the ServiceManagementService class, which man
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
@@ -31,6 +32,7 @@ public:
void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel); 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();
util::Map<std::string, ServiceBooking*> getServiceBookings(const std::string& customerID); 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 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 createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
@@ -38,7 +40,7 @@ public:
void completeJob(const std::string& jobID); void completeJob(const std::string& jobID);
void cancelCustomerServiceBookings(const std::string& customerID); void cancelCustomerServiceBookings(const std::string& customerID);
void cancelTechnicianJobs(const std::string& technicianID); void cancelTechnicianJobs(const std::string& technicianID);
void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage); void createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDs, double discountPercentage);
void removeComboPackage(const std::string& comboPackageID); void removeComboPackage(const std::string& comboPackageID);
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
@@ -6,6 +6,7 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept> #include <stdexcept>
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
@@ -244,3 +245,64 @@ void UserManagementService::saveUsers()
userFileManager.save(users); userFileManager.save(users);
notificationFileManager.save(notifications); notificationFileManager.save(notifications);
} }
/*
Function: getUsers
Description: Retrieves all users stored in the DataStore.
Parameter: None
Return type: util::Map<std::string, User*>
*/
util::Map<std::string, User*> UserManagementService::getUsers()
{
return m_dataStore.getUsers();
}
/*
Function: getUser
Description: Retrieves a specific user by ID from the DataStore.
Parameter: const std::string& userID - ID of the user
Return type: User*
*/
User* UserManagementService::getUser(const std::string& userID)
{
int index = m_dataStore.getUsers().find(userID);
if (index != -1)
{
return m_dataStore.getUsers().getValueAt(index);
}
return nullptr;
}
/*
Function: removeUser
Description: Marks a user as inactive in the DataStore instead of deleting them.
Parameter: const std::string& userID - ID of the user to remove
Return type: void
*/
void UserManagementService::removeUser(const std::string& userID)
{
int index = m_dataStore.getUsers().find(userID);
if (index != -1)
{
User* user = m_dataStore.getUsers().getValueAt(index);
if (user != nullptr)
{
user->setState(util::State::INACTIVE);
}
}
}
util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type)
{
util::Map<std::string, User*>& currentUsers = m_dataStore.getUsers();
util::Map<std::string, User*> filteredUsersMap;
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{
User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getUserType() == type)
{
filteredUsersMap.insert(currentUser->getId(), currentUser);
}
}
return filteredUsersMap;
}
@@ -15,7 +15,7 @@ namespace config
{ {
constexpr const char* DEFAULT_ADMIN_USERNAME = "admin"; constexpr const char* DEFAULT_ADMIN_USERNAME = "admin";
constexpr const char* DEFAULT_ADMIN_NAME = "admin"; constexpr const char* DEFAULT_ADMIN_NAME = "admin";
constexpr const char* DEFAULT_ADMIN_PASSWORD = ""; constexpr const char* DEFAULT_ADMIN_PASSWORD = "admin";
constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss"; constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss";
constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000"; constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000";
} }
@@ -22,7 +22,8 @@ namespace util
enum class PaymentMode enum class PaymentMode
{ {
ONLINE, ONLINE,
OFFLINE OFFLINE,
NOTSET
}; };
enum class PaymentStatus enum class PaymentStatus
@@ -33,8 +34,10 @@ namespace util
enum class ServiceJobStatus enum class ServiceJobStatus
{ {
PENDING,
STARTED, STARTED,
COMPLETED COMPLETED,
CANCELLED
}; };
enum class State enum class State
@@ -108,6 +111,8 @@ namespace util
return "ONLINE"; return "ONLINE";
case PaymentMode::OFFLINE: case PaymentMode::OFFLINE:
return "OFFLINE"; return "OFFLINE";
case PaymentMode::NOTSET:
return "NOTSET";
} }
throw std::invalid_argument("Invalid PaymentMode"); throw std::invalid_argument("Invalid PaymentMode");
} }
@@ -192,10 +197,14 @@ namespace util
{ {
switch (status) switch (status)
{ {
case ServiceJobStatus::PENDING:
return "PENDING";
case ServiceJobStatus::STARTED: case ServiceJobStatus::STARTED:
return "STARTED"; return "STARTED";
case ServiceJobStatus::COMPLETED: case ServiceJobStatus::COMPLETED:
return "COMPLETED"; return "COMPLETED";
case ServiceJobStatus::CANCELLED:
return "CANCELLED";
} }
throw std::invalid_argument("Invalid ServiceJobStatus"); throw std::invalid_argument("Invalid ServiceJobStatus");
} }
@@ -220,6 +229,14 @@ namespace util
{ {
return ServiceJobStatus::COMPLETED; return ServiceJobStatus::COMPLETED;
} }
if (value == "PENDING")
{
return ServiceJobStatus::PENDING;
}
if (value == "CANCELLED")
{
return ServiceJobStatus::CANCELLED;
}
throw std::invalid_argument("Invalid ServiceJobStatus string"); throw std::invalid_argument("Invalid ServiceJobStatus string");
} }
@@ -1,18 +1,17 @@
/* /*
File: Utility.h File: Utility.h
Description: Header file declaring utility functions used across the system, Description: Header file declaring utility functions used across the system
including cost calculation for services and combo packages.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include "ComboPackage.h"
#include "DataStore.h" #include "DataStore.h"
#include "FileHelper.h" #include "FileHelper.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "NotificationManagementService.h" #include "NotificationManagementService.h"
#include "Service.h" #include "Service.h"
#include "ComboPackage.h"
namespace util namespace util
{ {
@@ -8,34 +8,54 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <iomanip>
#include <iostream>
#include "AdminMenu.h" #include "AdminMenu.h"
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h" #include "InventoryItem.h"
#include "MenuHelper.h" #include "MenuHelper.h"
#include "OutputHelper.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "User.h"
#include "Utility.h"
#include "Validator.h"
/* /*
Function: showMenu Function: showMenu
Description: Displays the admin menu in a loop until the user chooses to logout. Description: Displays the admin menu and handles user input until logout is selected.
Handles exceptions and ensures smooth user interaction. Parameter: None
Parameters: Return type: void
- None
Returns:
- void
*/ */
void AdminMenu::showMenu() void AdminMenu::showMenu()
{ {
bool isMenuActive = true; while (true)
while (isMenuActive)
{ {
try try
{ {
int choice; int choice;
util::clear(); util::clear();
std::cout << "" << std::endl; std::cout << "Admin Menu"
<< "\n1. View Stock Levels"
<< "\n2. Add Inventory Item"
<< "\n3. Remove Inventory Item"
<< "\n4. Check Stock Availability"
<< "\n5. Assign Job to Technician"
<< "\n6. Add Technician"
<< "\n7. Remove Customer/Technician"
<< "\n8. Create Service"
<< "\n9. Remove Service"
<< "\n10. Create Combo Package"
<< "\n11. Remove Combo Package"
<< "\n12. View Notifications"
<< "\n13. Change Password"
<< "\n14. Logout"
<< "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
{ {
isMenuActive = false; break;
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
@@ -46,62 +66,489 @@ void AdminMenu::showMenu()
} }
} }
/*
Function: handleOperation
Description: Executes the corresponding admin operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if logout
*/
bool AdminMenu::handleOperation(int choice) bool AdminMenu::handleOperation(int choice)
{ {
switch (choice)
{
case 1:
viewStockLevels();
break;
case 2:
addInventoryItem();
break;
case 3:
removeInventoryItem();
break;
case 4:
checkStockAvailability();
break;
case 5:
assignJob();
break;
case 6:
addTechnician();
break;
case 7:
removeUser();
break;
case 8:
createService();
break;
case 9:
removeService();
break;
case 10:
createComboPackages();
break;
case 11:
removeComboPackage();
break;
case 12:
viewNotifications();
break;
case 13:
changePassword();
break;
case 14:
logout();
return false; return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
} }
/*
Function: logout
Description: Logs out the currently authenticated admin user.
Parameter: None
Return type: void
*/
void AdminMenu::logout() void AdminMenu::logout()
{ {
m_controller.logout();
} }
/*
Function: changePassword
Description: Allows the admin to change their password after validation.
Parameter: None
Return type: void
*/
void AdminMenu::changePassword() void AdminMenu::changePassword()
{ {
changePasswordHelper(m_controller);
} }
/*
Function: viewStockLevels
Description: Displays all active inventory items with their details
including ID, part name, quantity, and price.
Parameter: None
Return type: void
*/
void AdminMenu::viewStockLevels() void AdminMenu::viewStockLevels()
{ {
util::clear();
auto inventoryItems = m_controller.getInventoryItems();
std::cout << std::left << std::setw(15) << "Item ID"
<< std::setw(25) << "Part Name"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator)
{
const InventoryItem* item = inventoryItems.getValueAt(iterator);
if (item != nullptr)
{
if (item->getState() != util::State::INACTIVE)
{
std::cout << std::left << std::setw(15) << item->getId()
<< std::setw(25) << item->getPartName()
<< std::setw(10) << item->getQuantity()
<< std::setw(10) << item->getPrice()
<< std::endl;
}
}
}
} }
/*
Function: addInventoryItem
Description: Allows the admin to either add a new inventory item
or increase the quantity of an existing item.
Parameter: None
Return type: void
*/
void AdminMenu::addInventoryItem() void AdminMenu::addInventoryItem()
{ {
util::clear();
int choice, quantity;
double price;
std::string partName;
std::cout << "1. Add new item \n2. Add Quantity\nEnter your choice : ";
util::read(choice);
switch (choice)
{
case 1:
{
std::cout << "--------Enter Item Details----------\n";
std::cout << "Part Name : ";
util::read(partName);
std::cout << "Quantity : ";
util::read(quantity);
std::cout << "Price : ";
util::read(price);
m_controller.addInventoryItem(partName, quantity, price);
std::cout << "New Item " << partName << " added to the Inventory.\n";
break;
}
case 2:
{
auto inventoryItems = m_controller.getInventoryItems();
addQuantityToItem(inventoryItems, m_controller);
break;
}
}
util::pressEnter();
} }
/*
Function: removeInventoryItem
Description: Removes an active inventory item by marking it inactive
after user selection.
Parameter: None
Return type: void
*/
void AdminMenu::removeInventoryItem() void AdminMenu::removeInventoryItem()
{ {
util::clear();
auto inventoryItems = m_controller.getInventoryItems();
auto activeItems = filterActiveItems(inventoryItems);
int activeItemsSize = activeItems.getSize();
if (activeItemsSize == 0)
{
std::cout << "No items available in Inventory." << std::endl;
util::pressEnter();
return;
}
displayInventoryWithItems(activeItems);
int itemIndex;
std::cout << "Enter the index of the item to remove: ";
util::read(itemIndex);
if (itemIndex < 1 || itemIndex > activeItemsSize)
{
std::cout << "Invalid index selected." << std::endl;
util::pressEnter();
return;
}
const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1);
if (selectedItem != nullptr)
{
if(selectedItem->getState() != util::State::INACTIVE)
{
std::string selectedItemId = selectedItem->getId();
m_controller.removeInventoryItem(selectedItemId);
std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl;
}
}
util::pressEnter();
} }
/*
Function: checkStockAvailability
Description: Checks if a specific inventory item is available
and displays its details if active.
Parameter: None
Return type: void
*/
void AdminMenu::checkStockAvailability() void AdminMenu::checkStockAvailability()
{ {
util::clear();
std::string itemId;
std::cout << "Enter the Item Id : ";
util::read(itemId);
const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId);
if (selectedItem != nullptr)
{
if (selectedItem->getState() != util::State::INACTIVE)
{
std::cout << "Item Details\n";
std::cout << "---------------------------------------------\n";
std::cout << "Item ID : " << selectedItem->getId() << "\n";
std::cout << "Part Name : " << selectedItem->getPartName() << "\n";
std::cout << "Quantity : " << selectedItem->getQuantity() << "\n";
}
}
util::pressEnter();
} }
/*
Function: assignJob
Description: Allows the admin to assign pending service bookings to available technicians.
Creates job cards for selected services.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::assignJob() 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.";
}
}
}
util::pressEnter();
} }
/*
Function: createService
Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::createService() 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";
util::pressEnter();
} }
/*
Function: removeService
Description: Allows the admin to remove an existing service by selecting from available services.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::removeService() 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.";
}
util::pressEnter();
} }
/*
Function: addTechnician
Description: Adds a new technician after validating username, password, email, and phone number.
Parameter: None
Return type: void
*/
void AdminMenu::addTechnician() void AdminMenu::addTechnician()
{ {
util::clear();
std::string username, name, password, email, phoneNumber;
std::cout << std::left << std::setw(25) << "Enter Technician Username: ";
util::read(username);
std::cout << std::left << std::setw(25) << "Enter Technician Name: ";
util::read(name);
std::cout << std::setw(25) << "Enter Technician Password: ";
util::read(password);
if(!util::isPasswordValid(password))
{
std::cout << "Error: Password is invalid!";
util::pressEnter();
return;
}
std::cout << std::setw(25) << "Enter Technician Email: ";
util::read(email);
if(!util::isEmailValid(email))
{
std::cout << "Error: Email is invalid!";
util::pressEnter();
return;
}
std::cout << std::setw(25) << "Enter Technician Phone: ";
util::read(phoneNumber);
if(!util::isPhoneNumberValid(phoneNumber))
{
std::cout << "Error: Phone Number is invalid!";
util::pressEnter();
return;
}
m_controller.createTechnician(username, name, password, email, phoneNumber);
std::cout << "\nTechnician Added Successfully.\n";
util::pressEnter();
} }
/*
Function: removeUser
Description: Removes a selected active user (customer or technician) from the system.
Parameter: None
Return type: void
*/
void AdminMenu::removeUser() void AdminMenu::removeUser()
{ {
util::clear();
int indexChoice;
auto listOfUsers = m_controller.getUsers();
auto listOfActiveUsers = filterActiveUsers(listOfUsers);
int activeUserCount = listOfActiveUsers.getSize();
if (activeUserCount < 1)
{
std::cout << "No Active users." << std::endl;
util::pressEnter();
return;
}
displayAllActiveUsers(listOfActiveUsers, activeUserCount);
std::cout << "Enter the index of the user to delete : ";
util::read(indexChoice);
if (indexChoice < 1 || indexChoice > activeUserCount)
{
std::cout << "Error Invaild index.\n" << std::endl;
util::pressEnter();
return;
}
const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1);
if (userToRemove != nullptr)
{
std::string userIdToRemove = userToRemove->getId();
m_controller.removeUser(userIdToRemove);
std::cout << userToRemove->getUserName() << " removed Successfully.\n";
}
util::pressEnter();
} }
/*
Function: createComboPackages
Description: Creates a new combo package by selecting two active services and applying a discount.
Parameter: None
Return type: void
*/
void AdminMenu::createComboPackages() void AdminMenu::createComboPackages()
{ {
util::clear();
auto serviceList = m_controller.getServices();
const int NUMBER_OF_SERVICE_PER_PACKAGE = 2;
util::Vector<std::string> selectedServiceID;
for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++)
{
const Service* chosenService = nullptr;
while (true)
{
chosenService = selectServiceFromServices(serviceList);
if (chosenService == nullptr)
{
std::cout << "Failed to create combo package!";
util::pressEnter();
return;
}
bool alreadyChosen = false;
for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++)
{
if (selectedServiceID[iteratorOne] == chosenService->getId())
{
alreadyChosen = true;
break;
}
}
if (alreadyChosen)
{
std::cout << "Service already selected. Please choose a different one." << std::endl;
continue;
}
selectedServiceID.push_back(chosenService->getId());
util::clear();
break;
}
}
std::string packageName;
double discountPercentage;
std::cout << "Enter combo package name: ";
util::read(packageName);
std::cout << "Enter discount percentage: ";
util::read(discountPercentage);
if (discountPercentage < 0.0 || discountPercentage > 100.0)
{
std::cout << "Error: Discount percentage must be between 0 and 100." << std::endl;
util::pressEnter();
return;
}
m_controller.createComboPackage(packageName, selectedServiceID, discountPercentage);
std::cout << "Combo package '" << packageName << "' created successfully." << std::endl;
util::pressEnter();
} }
/*
Function: removeComboPackage
Description: Removes a selected combo package from the system.
Parameter: None
Return type: void
*/
void AdminMenu::removeComboPackage() void AdminMenu::removeComboPackage()
{ {
util::clear();
util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
std::string selectedComboPackageID = selectComboPackage(currentComboPackages);
if (selectedComboPackageID != "")
{
m_controller.removeComboPackage(selectedComboPackageID);
std::cout << "Combo Package removed successfully.\n";
}
else
{
std::cout << "Combo package removal failed.\n";
}
util::pressEnter();
} }
/* /*
@@ -1,8 +1,8 @@
/* /*
File: AdminMenu.h File: AdminMenu.h
Description: Declares the AdminMenu class which provides the administrative console menu in the Vehicle Service Management System. Description: Header file declaring the AdminMenu class, which provides
Supports operations such as inventory management, job assignment, service creation/removal, technician management, administrative operations such as inventory management,
combo package handling, notification viewing, and account management functions like logout and password change. user management, service configuration, and notifications.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
@@ -6,15 +6,21 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <iomanip> #include <iomanip>
#include "ComboPackage.h" #include "ComboPackage.h"
#include "CustomerMenu.h" #include "CustomerMenu.h"
#include "InputHelper.h"
#include "InventoryItem.h"
#include "Map.h"
#include "MenuHelper.h" #include "MenuHelper.h"
#include "Enums.h"
#include "InputHelper.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "Map.h"
#include "Service.h" #include "Service.h"
#include "ServiceBooking.h"
#include "Timestamp.h"
#include "User.h"
#include "Validator.h" #include "Validator.h"
#include "Vector.h" #include "Vector.h"
@@ -223,16 +229,97 @@ void CustomerMenu::selectComboPackage()
util::pressEnter(); 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
*/
void CustomerMenu::viewServiceHistory() 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;
}
util::pressEnter();
} }
/*
Function: completePayments
Description: Allows the customer to complete pending payments for invoices.
Validates invoice selection and payment mode before completing payment.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::completePayments() void CustomerMenu::completePayments()
{ {
util::clear();
util::Map<std::string, const Invoice*> currentInvoices = m_controller.getInvoicesByUser();
std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
return;
}
util::PaymentMode paymentMode = selectPaymentMode();
m_controller.completePayment(selectedID, paymentMode);
std::cout << "Payment completed successfully.\n";
util::pressEnter();
} }
/*
Function: viewInvoices
Description: Displays invoices associated with the customer by calling displayInvoices.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewInvoices() void CustomerMenu::viewInvoices()
{ {
util::clear();
util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser();
displayInvoices(currentUserInvoices);
util::pressEnter();
} }
/* /*
@@ -9,17 +9,514 @@ Date: 21-May-2026
#pragma once #pragma once
#include <iomanip> #include <iomanip>
#include <iostream>
#include <string> #include <string>
#include "ComboPackage.h"
#include "Controller.h" #include "Controller.h"
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h"
#include "Map.h" #include "Map.h"
#include "Notification.h" #include "Notification.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "Vector.h"
#include "Validator.h"
#include "Service.h" #include "Service.h"
#include "ComboPackage.h" #include "ServiceBooking.h"
#include "Timestamp.h"
#include "User.h"
#include "Utility.h" #include "Utility.h"
#include "Validator.h"
#include "Vector.h"
/*
Function: selectServicesToRemove
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
*/
inline 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: selectInventoryItems
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: listServiceBookings
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) << "TechnicianID"
<< std::endl;
for (int iterator = 0; iterator < bookingsSize; iterator++)
{
const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator);
if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
hasPendingService = true;
const User* currentAssignedTechnician = currentBooking->getAssignedTechnician();
std::cout << std::left
<< std::setw(10) << currentIndex
<< std::setw(10) << currentBooking->getId()
<< std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus())
<< std::setw(12) << currentBooking->getCustomerId()
<< std::setw(20) << currentBooking->getCustomer()->getName()
<< std::setw(15) << currentBooking->getVehicleNumber()
<< std::setw(15) << currentBooking->getVehicleBrand()
<< std::setw(15) << currentBooking->getVehicleModel()
<< std::setw(20) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getName().empty()) ? "Null" : currentAssignedTechnician->getName())
<< std::setw(15) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getId().empty()) ? "Null" : currentAssignedTechnician->getId())
<< std::endl;
serviceBookingsMap.insert(currentIndex++, currentBooking);
}
}
if (!hasPendingService)
{
std::cout << "No pending service available." << std::endl;
return false;
}
return true;
}
/*
Function: selectPendingServiceBookings
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
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
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: selectInvoiceFromUserForPayment
Description: Lists all pending invoices for the customer and allows selection by index.
Parameters:
- currentInvoices: util::Map<std::string, const Invoice*>&, map of customer invoices
Returns:
- std::string: ID of the selected invoice, or empty string if none selected
*/
static std::string selectInvoiceFromUserForPayment(const util::Map<std::string, const Invoice*>& currentInvoices)
{
int currentIndex = 1, choice;
util::Map<int, const Invoice*> pendingInvoicesForPayment;
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "BookingID"
<< std::setw(15) << "VehicleBrand"
<< std::setw(15) << "VehicleNumber"
<< std::setw(12) << "TechID"
<< std::setw(20) << "TechnicianName"
<< std::setw(10) << "Discount(%)"
<< std::setw(12) << "TotalAmount"
<< std::setw(20) << "InvoiceDate"
<< std::endl;
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{
const Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice && currentInvoice->getStatus() == util::PaymentStatus::PENDING)
{
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(12) << currentInvoice->getBookingId()
<< std::setw(15) << currentInvoice->getBooking()->getVehicleBrand()
<< std::setw(15) << currentInvoice->getBooking()->getVehicleNumber()
<< std::setw(12) << ((currentTechnician != nullptr && currentTechnician->getId() != "") ?
currentTechnician->getId() : "Null")
<< std::setw(20) << ((currentTechnician != nullptr && currentTechnician->getName() != "") ?
currentTechnician->getName() : "Null")
<< std::setw(10) << currentInvoice->getDiscountPercentage()
<< std::setw(12) << currentInvoice->getTotalAmount()
<< std::setw(20) << currentInvoice->getInvoiceDate().toString()
<< std::endl;
pendingInvoicesForPayment.insert(currentIndex++, currentInvoice);
}
}
if (pendingInvoicesForPayment.getSize() == 0)
{
std::cout << "No pending invoices available for payment.\n";
return "";
}
std::cout << "Select the Invoice to pay (Index): ";
util::read(choice);
int selectedIndex = pendingInvoicesForPayment.find(choice);
if (selectedIndex != -1)
{
const Invoice* selectedInvoice = pendingInvoicesForPayment.getValueAt(selectedIndex);
return selectedInvoice->getId();
}
else
{
std::cout << "Invalid choice.\n";
return "";
}
}
/*
Function: selectPaymentMode
Description: Allows the customer to select a payment mode (ONLINE or OFFLINE).
Parameters:
- None
Returns:
- util::PaymentMode: Selected payment mode
*/
static util::PaymentMode selectPaymentMode()
{
int choice;
std::cout << "Enter the payment Mode\n1.OFFLINE\n2.ONLINE\nChoice: ";
util::read(choice);
if (choice == 1)
{
std::cout << "Offline mode selected.\n";
return util::PaymentMode::OFFLINE;
}
else if (choice == 2)
{
std::cout << "Online mode selected.\n";
return util::PaymentMode::ONLINE;
}
else
{
std::cout << "Invalid choice, Offline mode selected.\n";
return util::PaymentMode::OFFLINE;
}
}
/*
Function: displayInvoices
Description: Displays detailed information for all invoices associated with the customer,
including booking details, technician, discount, total amount, payment status, and items used.
Parameters:
- currentUserInvoices: util::Map<std::string, const Invoice*>, customers invoices
Returns:
- void
Throws:
- std::runtime_error if a null invoice is encountered
*/
static void displayInvoices(util::Map<std::string, const Invoice*> currentUserInvoices)
{
if (currentUserInvoices.getSize() == 0)
{
std::cout << "No invoices found for this account." << std::endl;
util::pressEnter();
return;
}
else
{
for (int index = 0; index < currentUserInvoices.getSize(); index++)
{
const Invoice* currentInvoice = currentUserInvoices.getValueAt(index);
if (currentInvoice)
{
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
std::cout << "\nInvoice Details\n";
std::cout << "Booking ID: " << currentInvoice->getBookingId() << std::endl;
std::cout << "Vehicle Brand: " << currentInvoice->getBooking()->getVehicleBrand() << std::endl;
std::cout << "Vehicle Number: " << currentInvoice->getBooking()->getVehicleNumber() << std::endl;
std::cout << "Technician ID: " <<
((currentTechnician != nullptr && currentTechnician->getId() != "") ?
currentTechnician->getId() : "Null") << std::endl;
std::cout << "Technician Name: " <<
((currentTechnician != nullptr && currentTechnician->getName() != "") ?
currentTechnician->getName() : "Null") << std::endl;
std::cout << "Discount(%): " << currentInvoice->getDiscountPercentage() << std::endl;
std::cout << "Total Amount: " << currentInvoice->getTotalAmount() << std::endl;
std::cout << "Invoice Date: " << currentInvoice->getInvoiceDate().toString() << std::endl;
std::cout << "Payment Status: " << util::getPaymentStatusString(currentInvoice->getStatus()) << std::endl;
auto inventoryItemsInInvoice = currentInvoice->getParts();
std::cout << "\nItems Used:\n";
std::cout << std::left
<< std::setw(20) << "ItemName"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
std::cout << std::string(40, '-') << std::endl;
for (int iterator = 0; iterator < inventoryItemsInInvoice.getSize(); iterator++)
{
InventoryItem* currentItem = inventoryItemsInInvoice.getValueAt(iterator);
std::cout << std::left
<< std::setw(20) << currentItem->getPartName()
<< std::setw(10) << currentItem->getQuantity()
<< std::setw(10) << currentItem->getPrice()
<< std::endl;
}
}
else
{
throw std::runtime_error("Null invoice encountered while displaying invoices.");
util::pressEnter();
}
}
}
}
/*
Function: selectJobCardToComplete
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: selectNotification Function: selectNotification
@@ -125,6 +622,7 @@ Return type: void
*/ */
inline void changePasswordHelper(Controller& controller) inline void changePasswordHelper(Controller& controller)
{ {
util::clear();
std::string newPassword; std::string newPassword;
while (true) while (true)
{ {
@@ -144,6 +642,61 @@ inline void changePasswordHelper(Controller& controller)
} }
} }
/*
Function: filterActiveUsers
Description: Filters out inactive users and returns a map of active users.
Parameter: const util::Map<std::string, const User*>& listOfUsers - all users
Return type: util::Map<std::string, const User*>
*/
inline util::Map<std::string, const User*> filterActiveUsers(const util::Map<std::string, const User*>& listOfUsers)
{
util::Map<std::string, const User*> activeUsers;
int inventorySize = listOfUsers.getSize();
for (int index = 0; index < inventorySize; index++)
{
const User* user = listOfUsers.getValueAt(index);
if (user != nullptr && user->getState() != util::State::INACTIVE)
{
activeUsers.insert(user->getId(), user);
}
}
return activeUsers;
}
/*
Function: displayAllActiveUsers
Description: Displays all active users in a tabular format with index, ID, username, and type.
Parameter: util::Map<std::string, const User*>& activeUsers - active users list
int activeUserCount - number of active users
Return type: void
*/
inline void displayAllActiveUsers(util::Map<std::string, const User*>& activeUsers, int activeUserCount)
{
std::cout << std::left << std::setw(10) << "Index"
<< std::setw(15) << "User ID"
<< std::setw(25) << "Username"
<< std::setw(25) << "User Type"
<< std::endl;
for (int iterator = 0; iterator < activeUserCount; iterator++)
{
const User* user = activeUsers.getValueAt(iterator);
if (user != nullptr)
{
std::cout << std::left << std::setw(10) << (iterator + 1)
<< std::setw(15) << user->getId()
<< std::setw(25) << user->getUserName()
<< std::setw(25) << util::getUserTypeString(user->getUserType())
<< std::endl;
}
else
{
std::cout << "No users found.\n";
util::pressEnter();
return;
}
}
}
/* /*
Function: selectServiceFromServices Function: selectServiceFromServices
Description: Displays active services and allows the customer to select one by index. Description: Displays active services and allows the customer to select one by index.
@@ -164,6 +717,11 @@ inline const Service* selectServiceFromServices(const util::Map<std::string, con
for (int index = 0; index < services.getSize(); index++) for (int index = 0; index < services.getSize(); index++)
{ {
const Service* currentService = services.getValueAt(index); const Service* currentService = services.getValueAt(index);
if (currentService == nullptr)
{
throw std::runtime_error("Warning: Encountered a null service\n");
continue;
}
if (currentService->getState() != util::State::ACTIVE) if (currentService->getState() != util::State::ACTIVE)
{ {
continue; continue;
@@ -242,18 +800,7 @@ inline const ComboPackage* selectComboPackageFromPackages(const util::Map<std::s
} }
/* /*
Function: sendLowStockAlertsToAdmins (static helper) Function: getNotificationPreference
Description: Sends low stock alert notifications to all admin users for a given inventory item.
Parameters:
- inventoryManagementService: InventoryManagementService&, service used to send notifications
- inventoryItem: const InventoryItem*, pointer to the low-stock inventory item
- adminUsers: const util::Vector<User*>&, list of admin users to notify
Returns:
- None
*/
/*
Function: getNotificationPreference (static helper)
Description: Helper function to configure notification preferences for a specific service. Description: Helper function to configure notification preferences for a specific service.
Parameters: Parameters:
- serviceName: Name of the service for which notifications are being configured. - serviceName: Name of the service for which notifications are being configured.
@@ -285,3 +832,182 @@ inline bool getNotificationPreference(const std::string& serviceName)
} }
} }
/*
Function: filterActiveItems
Description: Filters out inactive inventory items and returns a map
containing only active items.
Parameter: const util::Map<std::string, const InventoryItem*>& inventoryItems -
map of all inventory items
Return type: util::Map<std::string, const InventoryItem*>
*/
inline util::Map<std::string, const InventoryItem*> filterActiveItems(const util::Map<std::string, const InventoryItem*>& inventoryItems)
{
util::Map<std::string, const InventoryItem*> activeItems;
int inventorySize = inventoryItems.getSize();
for (int index = 0; index < inventorySize; index++)
{
const InventoryItem* item = inventoryItems.getValueAt(index);
if (item != nullptr && item->getState() != util::State::INACTIVE)
{
activeItems.insert(item->getId(), item);
}
}
return activeItems;
}
/*
Function: displayInventoryWithItems
Description: Displays inventory items in a tabular format with index, ID,
part name, quantity, and price.
Parameter: util::Map<std::string, const InventoryItem*>& inventoryItems -
map of inventory items to display
Return type: void
*/
inline void displayInventoryWithItems(util::Map<std::string, const InventoryItem*>& inventoryItems)
{
int inventorySize = inventoryItems.getSize();
std::cout << std::left << std::setw(10) << "Index"
<< std::setw(15) << "Item ID"
<< std::setw(25) << "Part Name"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
for (int iterator = 0; iterator < inventorySize; iterator++)
{
const InventoryItem* item = inventoryItems.getValueAt(iterator);
if (item != nullptr)
{
std::cout << std::left << std::setw(10) << (iterator + 1)
<< std::setw(15) << item->getId()
<< std::setw(25) << item->getPartName()
<< std::setw(10) << item->getQuantity()
<< std::setw(10) << item->getPrice()
<< std::endl;
}
}
}
/*
Function: addQuantityToItem
Description: Allows the admin to select an active inventory item and
increase its stock quantity.
Parameter: util::Map<std::string, const InventoryItem*>& inventoryItems -
map of inventory items
Controller& m_controller - controller instance to update stock
Return type: void
*/
inline void addQuantityToItem(util::Map<std::string, const InventoryItem*>& inventoryItems, Controller& m_controller)
{
int itemIndex;
int quantity;
auto activeItems = filterActiveItems(inventoryItems);
int activeSize = activeItems.getSize();
if (activeSize == 0)
{
std::cout << "No active items available in Inventory" << std::endl;
return;
}
displayInventoryWithItems(activeItems);
std::cout << "Enter the index of the item to update: ";
util::read(itemIndex);
if (itemIndex < 1 || itemIndex > activeSize)
{
std::cout << "Invalid index selected." << std::endl;
return;
}
std::cout << "Enter quantity to add: ";
util::read(quantity);
if (quantity < 0)
{
std::cout << "The quantity should be Greater than 0." << std::endl;
return;
}
const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1);
if (selectedItem != nullptr)
{
std::string selectedItemId = selectedItem->getId();
m_controller.addInventoryItemStock(selectedItemId, quantity);
std::cout << "Updated " << selectedItem->getPartName()
<< " stock. New quantity: " << selectedItem->getQuantity()
<< std::endl;
}
else
{
std::cout << "Error: Selected item could not be found." << std::endl;
}
}
/*
Function: displayComboPackagesWithIndex
Description: Displays combo packages with index, ID, name, and discount percentage.
Parameter: util::Map<int, const ComboPackage*>& currentComboPackageIndexMap - combo packages map
Return type: void
*/
inline void displayComboPackagesWithIndex(util::Map<int, const ComboPackage*>& currentComboPackageIndexMap)
{
for (int iterator = 0; iterator < currentComboPackageIndexMap.getSize(); iterator++)
{
const ComboPackage* currentComboPackage = currentComboPackageIndexMap.getValueAt(iterator);
if (currentComboPackage == nullptr)
{
throw std::runtime_error("Error accessing the combopackage.\n");
}
if (iterator == 0)
{
std::cout << std::left
<< std::setw(8) << "Index"
<< std::setw(10) << "ID"
<< std::setw(20) << "Package Name"
<< std::setw(15) << "Discount (%)"
<< "\n";
}
std::cout << std::left
<< std::setw(8) << currentComboPackageIndexMap.getKeyAt(iterator)
<< std::setw(10) << currentComboPackage->getId()
<< std::setw(20) << currentComboPackage->getPackageName()
<< std::setw(15) << currentComboPackage->getDiscountPercentage()
<< "\n";
}
}
/*
Function: selectComboPackage
Description: Allows the admin to select an active combo package by index.
Parameter: util::Map<std::string, const ComboPackage*>& currentComboPackages - combo packages list
Return type: std::string - ID of the selected combo package
*/
inline std::string selectComboPackage(util::Map<std::string, const ComboPackage*>& currentComboPackages)
{
util::Map<int, const ComboPackage*> currentComboPackageIndexMap;
if (currentComboPackages.getSize() == 0)
{
throw std::runtime_error("No combo packages are available.\n");
}
int currentIndex = 1, choice, selectedIndex;
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
if (currentComboPackages.getValueAt(iterator)->getState() == util::State::INACTIVE)
{
continue;
}
currentComboPackageIndexMap.insert(currentIndex++, currentComboPackages.getValueAt(iterator));
}
if (currentComboPackageIndexMap.getSize() == 0)
{
throw std::runtime_error("No combo packages currently active.");
}
displayComboPackagesWithIndex(currentComboPackageIndexMap);
std::cout << "Enter your choice(Index): ";
util::read(choice);
selectedIndex = currentComboPackageIndexMap.find(choice);
if (selectedIndex != -1)
{
std::string selectedComboPackageID = currentComboPackageIndexMap.getValueAt(selectedIndex)->getId();
return selectedComboPackageID;
}
else
{
std::cout << "Enter a valid choice.\n";
return "";
}
}
@@ -1,16 +1,19 @@
/* /*
File: TechnicianMenu.cpp File: TechnicianMenu.cpp
Description: Implements the TechnicianMenu class which provides the technicians console interface Description: Implementation file containing the method definitions of the
in the Vehicle Service Management System. Handles menu display, user input, and TechnicianMenu class, including menu handling, job completion,
technician-specific operations such as completing jobs and viewing notifications. notification viewing, password management, and logout logic.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "Enums.h"
#include "TechnicianMenu.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h" #include "JobCard.h"
#include "MenuHelper.h" #include "MenuHelper.h"
#include "OutputHelper.h"
#include "Service.h"
#include "TechnicianMenu.h"
#include "Validator.h"
/* /*
Function: showMenu Function: showMenu
@@ -23,18 +26,22 @@ Returns:
*/ */
void TechnicianMenu::showMenu() void TechnicianMenu::showMenu()
{ {
bool isMenuActive = true; while (true)
while (isMenuActive)
{ {
try try
{ {
int choice; int choice;
util::clear(); util::clear();
std::cout << "" << std::endl; std::cout << "Technician Menu"
<< "\n1. Mark Job as Completed"
<< "\n2. View Notifications"
<< "\n3. Change Password"
<< "\n4. Logout"
<< "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
{ {
isMenuActive = false; break;
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
@@ -45,13 +52,60 @@ void TechnicianMenu::showMenu()
} }
} }
/*
Function: handleOperation
Description: Executes the corresponding technician operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if logout
*/
bool TechnicianMenu::handleOperation(int choice) bool TechnicianMenu::handleOperation(int choice)
{ {
switch (choice)
{
case 1:
completeJob();
break;
case 2:
viewNotifications();
break;
case 3:
changePassword();
break;
case 4:
logout();
return false; return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
} }
/*
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() 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";
}
util::pressEnter();
} }
/* /*
@@ -66,3 +120,26 @@ void TechnicianMenu::viewNotifications()
{ {
viewAndDeleteNotification(m_controller); viewAndDeleteNotification(m_controller);
} }
/*
Function: logout
Description: Logs out the currently authenticated technician user.
Parameter: None
Return type: void
*/
void TechnicianMenu::logout()
{
m_controller.logout();
}
/*
Function: changePassword
Description: Allows the technician to change their password after validation.
Parameter: None
Return type: void
*/
void TechnicianMenu::changePassword()
{
changePasswordHelper(m_controller);
}
@@ -1,7 +1,8 @@
/* /*
File: TechnicianMenu.h File: TechnicianMenu.h
Description: Declares the TechnicianMenu class which provides the technician-facing console menu in the Vehicle Service Management System. Description: Header file declaring the TechnicianMenu class, which provides
Supports operations such as viewing assigned jobs, completing jobs, and managing notifications. technician operations such as job completion, notification viewing,
password management, and logout functionality.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
@@ -18,4 +19,6 @@ public:
void showMenu(); void showMenu();
void completeJob(); void completeJob();
void viewNotifications(); void viewNotifications();
void logout();
void changePassword();
}; };
@@ -5,13 +5,13 @@ Description: Implementation file containing the method definitions of the
and customer registration logic. and customer registration logic.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "UserInterface.h"
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "Enums.h"
#include "User.h" #include "User.h"
#include "UserInterface.h"
#include "Validator.h" #include "Validator.h"
/* /*
@@ -7,6 +7,7 @@ Description: Header file declaring the UserInterface class, which provides
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include "Controller.h" #include "Controller.h"
#include "AdminMenu.h" #include "AdminMenu.h"