Compare commits

...

125 Commits

Author SHA1 Message Date
Avinash Rajesh 1032fc64bd Commit aee6356e: Implement Confirm Payment Functionality
<User Story> Complete Payments - 1797</User Story>

<Changes>
1. Added Controller::getAllInvoices
   - Retrieves all invoices from PaymentManagementService and returns them as a read-only map.
2. Implemented Controller::confirmPayment
   - Delegates payment confirmation for a given invoice ID to PaymentManagementService.
3. Introduced PaymentManagementService::getAllInvoice
   - Provides access to all invoices stored in the datastore.
4. Added PaymentManagementService::confirmPayment
   - Confirms payment for a specific invoice, updates payment date and status, and sends notification.
5. Extended util::PaymentStatus enum
   - Added PAID status and updated string conversion.
6. Integrated AdminMenu::confirmPayment
   - Validates invoice list, filters by status, allows selection, and confirms payment.
7. Updated CustomerMenu::completePayments
   - Uses parameterized status filtering for invoice selection.
8. Enhanced MenuHelper::selectInvoiceFromUserForPayment
   - Accepts requiredStatus parameter for flexible filtering.
9. Adjusted AdminMenu options
   - Added "Confirm Payment" before Logout.
</Changes>

<Test>
Acceptance Criteria:
1. Admin selects "Confirm Payment" from menu.
   - Verify system prompts and displays invoices filtered by status.
2. Admin selects invoice with status = PAID.
   - Verify payment confirmation updates date, sets status, and sends notification.
3. Admin attempts confirmation with empty invoice list.
   - Verify error message: "No pending invoices available for confirmation."
4. Customer completes payment.
   - Verify selection uses util::PaymentStatus::PENDING and payment flow works correctly.
5. Invalid invoice ID entered.
   - Verify system throws runtime_error with "Payment failed: invalid invoice ID."

Precondition:
1. Admin logged into system.
2. At least one invoice exists in datastore.
3. Notification system available.

Steps:
1. Navigate to Admin menu → Confirm Payment.
2. Select invoice with PAID status.
3. Confirm payment and check notification.
4. Attempt with empty invoice list.
5. Attempt with invalid invoice ID.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-06-01 17:30:27 +05:30
joelthomastrenser cfd1a2b675 Merged PR 1154: Implement Update Job Status for technician
- Renamed Controller and ServiceManagementService methods from completeJob to updateJobStatus for clarity and flexibility.
- Enhanced ServiceManagementService::updateJobStatus to support transitions:
- STARTED → INPROGRESS
- INPROGRESS → COMPLETED (with invoice generation and customer notification).
- Added INPROGRESS state to ServiceJobStatus enum and updated string conversion utilities.
- Introduced filterJobCards helper to generalize job filtering by status.
- Updated TechnicianMenu to allow technicians to select job type (Started/Inprogress) and update status accordingly.
- Improved job display to show current status and truncated service names for readability.

Related work items: #1798
2026-06-01 17:25:28 +05:30
Jissin Mathew 70ec47df04 Fix review comments 2026-06-01 16:49:57 +05:30
Jissin Mathew 2ea77bf9b6 Implement Update Job Status for technician
<UserStory> SER1798: Update Job Status </UserStory>

<Changes>
    1. Renamed Controller and ServiceManagementService methods from completeJob to updateJobStatus for clarity and flexibility.
    2. Enhanced ServiceManagementService::updateJobStatus to support transitions:
       - STARTED → INPROGRESS
       - INPROGRESS → COMPLETED (with invoice generation and customer notification).
    3. Added INPROGRESS state to ServiceJobStatus enum and updated string conversion utilities.
    4. Introduced filterJobCards helper to generalize job filtering by status.
    5. Updated TechnicianMenu to allow technicians to select job type (Started/Inprogress) and update status accordingly.
    6. Improved job display to show current status and truncated service names for readability.
</Changes>

<Test>

 Acceptance Criteria:
 1. Technician can select a job with status STARTED and update it to INPROGRESS.
 2. Technician can select a job with status INPROGRESS and update it to COMPLETED.
 3. Completed bookings automatically generate invoices and send notifications to customers.
 4. Job status updates are reflected in the technician’s job list and customer view.

 Precondition:
 1. Technician is logged into the system.
 2. Assigned job cards exist with valid statuses (STARTED or INPROGRESS).
 3. Datastore and payment service are available.

 Steps:
 1. Navigate to Technician menu and choose "Update Job Status".
    - Verify that the system prompts for job type selection (Started/Inprogress).
 2. Select a job card from the filtered list.
    - Verify that the job card details are displayed with status.
 3. Confirm update.
    - Verify that the job status changes correctly.
 4. For jobs updated to COMPLETED:
    - Verify that the booking status is updated, invoice is generated, and notification is sent.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>

#1798
2026-06-01 16:49:56 +05:30
joelthomastrenser 972e353832 Merged PR 1152: Vehicle Service System v1.0.0.0
Features Included:

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

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

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

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

Fixes #1793

Related work items: #1646, #1793
2026-05-28 10:35:54 +05:30
joelthomastrenser b1b6125d88 Fix: create missing directories before file creation
Changes:
- Added ensureDirectoryExists() helper using _mkdir()
- Automatically create missing directories before file operations
- Added FileHelper include in FileManager
- Removed placeholder files/README.md

Fixes #1793
2026-05-28 10:32:36 +05:30
joelthomastrenser e739ec6ee2 Merged PR 1134: Fix Invoice Deserialization Failure for PaymentMode::NOTSET
Changes:

- Added support for PaymentMode::NOTSET in payment mode string-to-enum conversion.
- Improved invoice table column labels and spacing for better readability in invoice display screens.

Fixes #1789

Related work items: #1646, #1789
2026-05-27 19:51:59 +05:30
joelthomastrenser f78e02ed3d Fix: handle NOTSET payment mode during invoice deserialization
Changes:

- Added support for PaymentMode::NOTSET in string-to-enum conversion
  to prevent invoice deserialization failures during system startup
- Improved invoice table column labels and spacing for better readability
  and alignment in invoice display screens

Fixes #1789
2026-05-27 18:47:49 +05:30
Avinash Rajesh 807490443e Merged PR 1128: Fix customer removal flow, admin inventory UI issues, and user display improvements
Changes:

- Refactored customer and technician removal flow:
  - Ensured linked job cards and service bookings are properly cancelled.
  - Centralized cancellation logic with processBookingCancellation helper for consistent notifications, technician reassignment, and inventory restoration.
  - Prevented duplicate inventory restocking during customer removal.
  - Preserved customer references and IDs correctly during booking cancellation.

- Admin inventory management improvements:
  - Added heading output to Remove Inventory Item submenu for clearer context.
  - Prevented service creation with empty inventory selection by adding validation and early return.
  - Improved combo package creation by simplifying null checks with modern idioms.
  - Enhanced inventory selection flow:
    - Clear screen and context header for better UX.
    - Prevent duplicate item selection by checking already chosen items.
    - Changed exit option from -1 to 0 for consistency.
    - Added pressEnter prompt after successful item addition.
  - Simplified pointer checks using concise conditions (e.g., if (item)).

- User management UI fix:
  - Updated active user display in Remove User menu to include Full Name column, ensuring administrators have complete visibility when managing users.

Fixes #1788
Fixes #1778
Fixes #1781

Related work items: #1778, #1781, #1788
2026-05-27 18:38:17 +05:30
Avinash Rajesh b7bc1f574d Implement Review Fixes 2026-05-27 17:32:36 +05:30
Avinash Rajesh b25b3d59cf Fix Admin Menu Remove User Incomplete Data
- Updated active user display to include Full Name column.
- Ensured both header and row output show full name alongside ID, username, and user type.
- Improved clarity of Remove User submenu by presenting complete user information.

Fixes #1788
2026-05-27 17:12:23 +05:30
Avinash Rajesh c1bd2a6ef1 Fix Admin Inventory Management UI Issues and Workflow Enhancements
- Added heading output to Remove Inventory Item submenu for clearer user context.
- Prevented service creation with empty inventory selection by adding validation and early return.
- Improved combo package creation by simplifying null checks with modern idioms.
- Enhanced inventory selection flow:
  - Clear screen and context header for better UX.
  - Prevent duplicate item selection by checking already chosen items.
  - Changed exit option from -1 to 0 for consistency.
  - Added pressEnter prompt after successful item addition.
- Simplified pointer checks using concise conditions (e.g., if (item)).

Fixes #1778
2026-05-27 17:12:23 +05:30
Avinash Rajesh 859f7bbeaa Fix Customer Removal and Cancellation Handling Issues
- Refactored customer and technician removal flow to ensure linked job cards and service bookings are properly cancelled.
- Added inventory restoration logic to avoid duplicate restocking when cancelling bookings.
- Introduced processBookingCancellation helper for consistent cancellation handling, notifications, and technician reassignment.
- Updated UserManagementService::removeUser to invoke appropriate cancellation routines based on user type.
- Ensured customer references and IDs are preserved correctly during booking cancellation.

Fixes #1781
2026-05-27 17:12:20 +05:30
Jissin Mathew d6cc6fc04f Merged PR 1129: Fix view invoices, combo packages, and technician menu UI issues
Changes
- Added tabular invoice list with selection before full details
- Displayed Payment Mode in detailed invoice view
- Removed duplicate pressEnter() calls and improved console messages
- Changed combo package bookings to start with PENDING status
- Added filterComboPackages to list only active packages
- Improved CustomerMenu combo package selection with clearer messages and formatting
- Enhanced output with console clearing, spacing, and success feedback
- Added truncateString utility for consistent display of long names
- Updated filter functions to use reference parameters for efficiency
- Cleared console before displaying Complete Job screen
- Improved submenu header and formatting for clarity
- Prevented table headers from showing when no jobs exist
- Refined job completion flow with consistent messages

Fixes #1779
Fixes #1782
Fixes #1784

Related work items: #1779, #1782, #1784
2026-05-27 17:09:18 +05:30
Jissin Mathew 62cd7dcc89 Implement Review Fixes 2026-05-27 17:09:03 +05:30
Jissin Mathew c67bf962c1 Fix Customer Menu View Invoices UI and Navigation Issues
- Added tabular invoice list for better navigation
- Enabled user to select an invoice before viewing full details
- Displayed Payment Mode in detailed invoice view
- Removed duplicate pressEnter() calls
- Improved console messages and formatting for clarity

Fixes #1784
2026-05-27 16:55:14 +05:30
Jissin Mathew efd8b32a5f Fix Combo Package Status and Creation Flow Issues
- Changed combo package bookings to start with PENDING status
- Added filterComboPackages to list only active packages
- Improved CustomerMenu combo package selection with clearer messages and formatting
- Enhanced output with console clearing, spacing, and success feedback
- Added truncateString utility for consistent display of long names
- Updated filter functions to use reference parameters for efficiency

Fixes #1779
2026-05-27 16:53:30 +05:30
Jissin Mathew 01596e825e Fix Technician Menu Complete Job UI Issues
- Cleared console before displaying Complete Job screen
- Improved submenu header and formatting for clarity
- Prevented table headers from showing when no jobs exist
- Refined job completion flow with consistent messages

Fixes #1782
2026-05-27 16:53:29 +05:30
joelthomastrenser fb50aeba47 Merged PR 1127: Fix notification UI formatting, payment flow issues, and observer cleanup
Changes:

- Fix notification table alignment issues in admin notification screens
- Add proper spacing for notification title column display
- Remove unnecessary tab spacing from Configure Notification Preferences heading
- Change ServiceBooking ID prefix to avoid conflict with Service IDs
- Remove unnecessary newline characters from service booking completion notifications
- Detach removed users from all service observer lists during user removal
- Fix Complete Payments screen clearing immediately after heading display
- Improve table spacing in Complete Payments screen
- Prevent invalid payment mode selection from defaulting to OFFLINE mode

Fixes #1780
Fixes #1783
Fixes #1777
Fixes #1786

Related work items: #1777, #1780, #1783, #1786
2026-05-27 16:49:20 +05:30
joelthomastrenser defee9aa15 Fix ServiceBooking ID prefix and notification messages
- change ServiceBooking ID prefix from `SRV` to `SBK`
- add customer notification when technician is assigned to booking
- fix typo in job completion exception message
- remove unnecessary newline characters from completion notifications

Fixes #1780
2026-05-27 16:02:23 +05:30
joelthomastrenser 67e5917a57 Fix: improve complete payments table formatting and payment mode validation
- Increased spacing between invoice table columns for better readability
- Updated invoice table headers with clearer labels
- Prevented screen clear before invoice listing display
- Changed payment mode selection to re-prompt on invalid input instead of defaulting to offline mode
- Removed unnecessary blank line before service listing display

Fixes #1786
2026-05-27 13:02:40 +05:30
joelthomastrenser 83e2bed432 Fix: improve notification display formatting and add global exception handling
- add truncateString utility for long notification titles
- improve notification table alignment
- remove unnecessary heading spacing in notification preferences
- add application-level exception handling in UserInterface::run()

Fixes #1777
2026-05-27 12:19:34 +05:30
joelthomastrenser a9c8ec93b7 Fix: detach removed users from service observers
- detach users from InventoryManagementService observers during removal
- detach users from PaymentManagementService observers during removal
- detach users from ServiceManagementService observers during removal

Fixes #1783
2026-05-27 11:10:59 +05:30
Jissin Mathew 13b7d6d40a Merged PR 1114: Fix Admin Menu, Service Management, Technician Assignment, and Invoice Display Issues
**Changes:**

- Fixed booking status flow (PENDING → STARTED) during job card creation
- Updated purchaseService to initialize bookings with PENDING status
- Filtered active users and services before listing/selection
- Improved Assign Job flow: pending bookings only, clearer technician prompts, consistent feedback
- Enhanced View Invoices: reference parameter, empty items handling, improved formatting
- Added filterActiveServices helper for consistent active service filtering
- Fixed Remove Service to also deactivate dependent combo packages
- Improved Create Combo Packages: cancel option, confirmation step, duplicate/edge case handling
- Updated Remove Combo Package to handle empty states gracefully without exceptions

Related work items: #1646, #1740, #1744, #1745, #1747, #1749, #1752
2026-05-26 21:26:37 +05:30
joelthomastrenser 665e83d56a Implement review fixes 2026-05-26 21:25:02 +05:30
Jissin Mathew 8268b90d82 Fix Service Removal and Combo Package Management Issues
- Added ComboPackage dependency check in removeService; deactivates related packages when a service is removed.
- Added filterActiveServices helper to list only active services.
- Updated removeService and removeComboPackage with headings, empty-state checks, and consistent success/error messages.
- Enhanced createComboPackages:
  - Uses active services only.
  - Added cancel option and confirmation after first selection.
  - Prevented duplicate selection and infinite loop when limited services exist.
  - Improved feedback when all available services are selected.
- Updated selectServicesToRemove and selectComboPackage to handle empty states gracefully without exceptions.

Fixes #1749
2026-05-26 21:13:40 +05:30
Jissin Mathew 7646ce6644 Fix Assign Job to Technician issues and View invoices issues
- Assign Job to Technician:
  - Added heading for clearer user guidance.
  - Filtered only pending service bookings for assignment.
  - Improved technician listing and selection with clearer prompts.
  - Ensured booking status transitions correctly from PENDING to STARTED when job cards are created.
  - Enhanced feedback messages for technician availability and job card creation.

- View Invoices:
  - Added heading "View Invoices" for better UI consistency.
  - Updated displayInvoices to take map by reference for efficiency.
  - Improved formatting of invoice details with consistent spacing and line breaks.
  - Added handling for empty invoice parts list (shows "No inventory items used").
  - Enhanced error messages when encountering null invoices.

Fixes #1745
Fixes #1752
2026-05-26 21:13:13 +05:30
Jissin Mathew 05499e4890 Fix Create Service Submenu
- Added heading "Create Service" to submenu for clearer user guidance.
- Ensured console clears before service creation for consistent UI behavior.
- Filtered active inventory items before selection to avoid showing inactive items.
- Updated prompts with improved formatting and spacing (e.g., labour cost input, success message).
- Refactored selectInventoryItems:
  - Added "Select Required Items" heading for clarity.
  - Skipped null or inactive items during listing.
  - Improved empty inventory message ("No Items Present, Inventory empty").
  - Enhanced success and error messages with consistent line breaks.
  - Simplified logic for item selection and exit handling.

Fixes #1747
2026-05-26 21:12:17 +05:30
Jissin Mathew 3b82648e45 Fix Add Technician submenu
- Updated AdminMenu::addTechnician:
  - Added heading "Add Technician" for better user guidance.
  - Removed setw formatting, replaced with simpler prompts.
  - Ensured console clears before operation for consistency.
  - Improved error messages for password, email, and phone validation with line breaks for readability.
  - Enhanced success message with consistent spacing.
- Minor cleanup in TechnicianMenu.cpp by adding a blank line after file header for formatting consistency.

Fixed #1744
2026-05-26 21:12:16 +05:30
Jissin Mathew 937ba2e7cf Fix Add Inventory Item Issues
- Added heading "Add Inventory Item" to submenu for clearer user guidance.
- Updated option text from "Add Quantity" to "Restock Item".
- Ensured console clearing (util::clear) before add item and restock operations.
- Reformatted prompts with consistent spacing and line breaks (e.g., "Enter Item Details", "Select Item to Restock").
- Added default case handling in AdminMenu for invalid choices.
- Enhanced MenuHelper output:
  - Extra line breaks for readability.
  - Improved error messages ("Invalid index selected", "No active items available").
  - Clearer success message when updating stock with new quantity.

Fixes #1740
2026-05-26 21:12:16 +05:30
Avinash Rajesh f63e4056f2 Merged PR 1110: Fix user management, customer menu, inventory, notification, and validation issues
Changes:
- Added validation in AdminMenu::viewStockLevels and improved stock level formatting with headers, column widths, and pressEnter prompts
- Enhanced AdminMenu::checkStockAvailability with header, clear screen, and missing item validation
- Updated AdminMenu::removeUser with header and excluded ADMIN users from active list
- Improved CustomerMenu::completePayments with pending invoice checks, error handling, and clearer headers
- Refined selectInvoiceFromUserForPayment in MenuHelper.h (inline, clear screen, updated headers)
- Added "View Service History" header in CustomerMenu::viewServiceHistory and widened table columns
- Improved notification handling: added headers, empty list validation, pressEnter prompts, and adjusted column widths
- Simplified notification titles in Inventory, Payment, and Service Management services
- Strengthened UserManagementService::updateUserDetails with duplicate checks (email, phone), clearer errors, and Validator integration
- Implemented new duplicate validation functions (isUsernameDuplicate, isPhoneDuplicate, isEmailDuplicate) in Validator utilities
- Updated CustomerMenu::updateDetails with header, improved error/success message formatting, and validation integration

Related work items: #1646, #1739, #1741, #1742, #1746, #1748, #1750
2026-05-26 21:05:38 +05:30
joelthomastrenser febfa45e4a Implement review fixes
Changes:

 - Strengthened UserManagementService::updateUserDetails by checking duplicates only when email/phone are changed, preventing false errors
 - Updated AdminMenu::viewStockLevels header text from "View Stock Level" to "View Stock Levels" for consistency
 - Cleaned up CustomerMenu::updateDetails by removing unused user list retrieval and improving header/message formatting
2026-05-26 21:03:22 +05:30
Avinash Rajesh 33cbb1dac3 Fix Update Profile and User Validation Issues
- Included Validator.h in UserManagementService.cpp for duplicate checks.
- Enhanced updateUserDetails in UserManagementService to validate:
  - Throw error if user does not exist.
  - Throw error if email already exists among active users.
  - Throw error if phone number already exists among active users.
- Implemented new duplicate validation functions in Validator.cpp:
  - isUsernameDuplicate
  - isPhoneDuplicate
  - isEmailDuplicate
- Declared new duplicate validation functions in Validator.h.
- Updated CustomerMenu::updateDetails:
  - Added "Update Details" header for clarity.
  - Improved error messages with newline formatting.
  - Added success message with newline formatting.

Fixes #1746
2026-05-26 20:24:36 +05:30
Avinash Rajesh 80b91f3f1b Fix View Service History and View Notification Issue
- Updated sendNotification in InventoryManagementService, PaymentManagementService, and ServiceManagementService to use only the provided title instead of prefixing with service name.
- Added "View Service History" header in CustomerMenu::viewServiceHistory for clarity.
- Adjusted column widths in service history table for better alignment:
  - Booking ID column widened to 15.
  - Vehicle Brand, Vehicle Number, Vehicle Model, Discount %, and Status columns widened to 20.
- Updated output formatting in CustomerMenu::viewServiceHistory to match new widths.
- Added "View and Delete Notification" header in MenuHelper::viewAndDeleteNotification for clarity.
- Moved empty notification validation from selectNotification to viewAndDeleteNotification:
  - Displays "No notifications available." message.
  - Added util::pressEnter() prompt before returning when no notifications exist.
- Increased Notification title column width from 30 to 35 in selectNotification for improved readability.

Fixes #1748
2026-05-26 20:23:18 +05:30
Avinash Rajesh a87af89a8a Fix Complete Payment Issue
- Added "Complete Payments" header in CustomerMenu::completePayments for clarity.
- Implemented validation to check if invoices list is empty and display appropriate message.
- Added logic to verify presence of pending invoices before proceeding with payment.
- Enhanced error handling to show "Payment failed" with pressEnter prompt when no invoice is selected.
- Updated selectInvoiceFromUserForPayment in MenuHelper.h:
  - Changed function to inline and added util::clear() at start.
  - Updated column headers to "Technician ID" and "Technician Name" for clarity.
- Removed temporary AdminMenu.cpp file from enc_temp_folder.

Fixes #1750
2026-05-26 20:23:16 +05:30
Avinash Rajesh f1ca8c2a58 Fix Remove User Issue
- Added "Remove User" header in AdminMenu::removeUser for clarity.
- Updated filterActiveUsers in MenuHelper.h to exclude ADMIN users from the active user list.

Fixes #1742
2026-05-26 20:23:16 +05:30
Avinash Rajesh d55bbb6349 Fix Check stock availability Issue and Add error message
- Added "Check Stock Availability" header in AdminMenu::checkStockAvailability for clarity.
- Updated prompt text to "Enter the Item ID" for consistency.
- Added util::clear() after reading Item ID to refresh the screen before displaying results.
- Implemented validation to show "Item not Found" message when the entered ID does not exist in inventory.
Fix #1741
2026-05-26 20:23:15 +05:30
Avinash Rajesh ae488f5670 Fix View Stock Level and improve error messages
- Added validation in AdminMenu::viewStockLevels to check for empty inventory before displaying.
- Added validation in AdminMenu::viewStockLevels to ensure only active items are shown.
- Added "View Stock Level" header for clarity.
- Adjusted column widths for Quantity and Price to 15 for better alignment.
- Added final newline and util::pressEnter() prompt after displaying stock levels.
Fixes  #1739
2026-05-26 20:23:15 +05:30
joelthomastrenser d8f7e46180 Merged PR 1108: Fix authentication, registration, customer menu, utility, and structural issues
Changes:

- Fixed login error handling and authentication validation issues
- Added duplicate checks during customer registration
- Fixed missing headers and message formatting issues in Login/Register screens
- Improved common utility and console interaction behavior
- Fixed Select Individual Service issues (booking status and empty service handling)
- Fixed Select Combo Package issues (header and empty combo package handling)
- Fixed low stock alert loop condition bug
- Updated MenuHelper.h functions from static to inline

Related work items: #1646, #1736, #1737, #1738, #1743, #1751, #1753, #1754
2026-05-26 20:14:40 +05:30
joelthomastrenser 3d7944f77d Impelement review fixes 2026-05-26 20:12:57 +05:30
joelthomastrenser 9439202c5a Fix: improve combo package selection UI and empty state handling
- add Select a Combo Package header
- show message when no combo packages are available
- improve combo package table header labels

Fixes #1743
2026-05-26 18:04:05 +05:30
joelthomastrenser e6faa63b88 Fix: improve customer service selection flow and booking status
- Set new service bookings to PENDING instead of STARTED
- Show message when no services are available
- Add Select a Service header
- Add Enter Vehicle Details header
- Improve service selection screen flow

Fixes #1753
2026-05-26 17:46:11 +05:30
joelthomastrenser 31e660bc9e Fix: add duplicate user validation and update register customer UI
- add username duplicate validation
- add email duplicate validation
- add phone duplicate validation
- move duplicate checks to Validator utility
- add Register Customer header
- update registration success message

Fixes #1737
2026-05-26 16:47:11 +05:30
joelthomastrenser 5fd0a47459 Fix off-by-one error in sendLowStockAlerts loop
Fixes #1751
2026-05-26 14:22:41 +05:30
joelthomastrenser fb509ccb3f Change static functions to inline in MenuHelper
Fixes #1754
2026-05-26 12:40:27 +05:30
joelthomastrenser 8d07b11eae Fix login validation and improve error messages
- Check if user account is inactive before allowing login
- Add password confirmation in change password dialog
- Prevent changing password to the same value
- Standardize error messages to say "Invalid index" instead of "Invalid choice"
- Add blank line before system pause prompt
- Add "Change Password" header to change password screen
- Show error message when login fails

Fixes #1738
Fixes #1736
2026-05-26 12:18:38 +05:30
Jissin Mathew 1e11903cca Merged PR 1069: fix: cleanup and small improvements
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:15:26 +05:30
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 089fe496b2 Merged PR 1042: Service-Management-1553, Payment-Management-1598
**Service Management**
**SER001 - Assign Job to Technician:** Allows admins to assign service jobs to technicians for efficient work distribution.
**SER002 - Create Service:** Allows admins to create new services that customers can select and book.
**SER003 - Remove Service:** Allows admins to remove outdated services from the system.
**SER004 - View Service History:** Allows customers to view the status and history of their booked services.
**SER005 - Update Service Status:** Allows technicians to update service progress so customers can track it.

**Payment Management**
**PAY001 - Generate Invoice:** Automatically creates invoices with service, parts, and labor cost details for customer payments.
**PAY002 - Complete Payments:** Allows customers to complete pending payments and receive confirmation.
**PAY003 - View Invoices:** Allows customers to view invoice details for their purchased services.

Related work items: #1553, #1577, #1578, #1579, #1580, #1581, #1598, #1599, #1600, #1601, #1655, #1656, #1679, #1680
2026-05-25 20:07:59 +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
joelthomastrenser 1e8fd2829f Fix PR review comments and refactor menu helper logic
Changes:
- Added name parameter to createTechnician for consistency
- Added function headers for notification-related methods in InventoryManagementService
- Used variables for notification title and message instead of passing strings directly
- Fixed payment reminder notification message formatting
- Moved common helper functions to MenuHelper.h
- Updated CustomerMenu to use shared helper functions instead of duplicate code
- Added missing includes in MenuHelper.h
- Removed redundant helper code from CustomerMenu.cpp
- Minor formatting and comment cleanup
2026-05-25 15:46:11 +05:30
joelthomastrenser 28e4b17c63 Merge branch 'feature-file-management' into feature-1551-1561-1708 2026-05-25 14:24:21 +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
joelthomastrenser 72860edd18 Merge branch 'feature-notification-management' into feature-1551-1561-1708 2026-05-25 11:48:25 +05:30
Avinash Rajesh c5f87a0c68 Add standardized documentation headers 2026-05-25 10:54:35 +05:30
Jissin Mathew 014d4eaa0d Align enum string values with actual State names 2026-05-22 17:12:47 +05:30
Jissin Mathew 388e459a5a Add documentation headers across system modules 2026-05-22 16:52:06 +05:30
joelthomastrenser 53713f444b Implement serialization/deserialization and persistent storage across services
- Add serialize/deserialize support for core models
- Add file-based load/save functions in management services
- Introduce FileManager, Config, Utility and helper utilities
- Persist observer IDs for notification services
- Resolve object relationships during load (services, bookings, invoices, job cards)
- Add controller-level loadSystemData/saveSystemData
- Load data at app startup and save on shutdown
2026-05-22 16:50:28 +05:30
Avinash Rajesh 34cb64ab1b Add standardized documentation headers 2026-05-22 13:26:02 +05:30
Jissin Mathew f1d146a37c Add documentation headers across system modules 2026-05-22 13:21:51 +05:30
Jissin Mathew 500eb95f12 Add documentation headers across system modules 2026-05-22 12:49:14 +05:30
Avinash Rajesh 6ca659c573 Add standardized documentation headers 2026-05-22 11:27:49 +05:30
Jissin Mathew 340f00deef Merge branch 'feature-notification-management-not006' into feature-notification-management 2026-05-21 21:07:17 +05:30
Jissin Mathew 0933db41a5 Merge branch 'feature-notification-management-not005' into feature-notification-management 2026-05-21 21:00:20 +05:30
Jissin Mathew 8a595a5893 Merge branch 'feature-notification-management-not004' into feature-notification-management 2026-05-21 20:54:20 +05:30
Jissin Mathew a8f934c7c5 Merge branch 'feature-notification-management-not003' into feature-notification-management 2026-05-21 20:48:41 +05:30
Jissin Mathew 166cc02aaa Merge branch 'feature-notification-management-not002' into feature-notification-management 2026-05-21 20:46:02 +05:30
joelthomastrenser b8e87ade0f Implement View Customer Notifications
<UserStory> NOT001: View Customer Notifications </UserStory>

<Changes>
1. Added shared notification helper functions to display notifications in tabular format, support notification selection, and show full notification details.
2. Implemented notification deletion logic in Controller and UserManagementService to remove notifications for the authenticated user after viewing.
3. Updated CustomerMenu::viewNotifications() to use the shared notification viewing and deletion flow.
</Changes>

<Test>

Precondition:
1. Customer is registered in the system.
2. Customer is logged into the system.
3. Customer has one or more notifications available.

Steps:
1. Navigate to “View Notifications” from the customer menu.
- Verify that the system displays the list of notifications with title and timestamp.

2. Select a notification from the displayed list.
   - Verify that the system displays the full notification details including message.

3. View the selected notification and continue.
   - Verify that the viewed notification is deleted from the system.

4. Navigate to “View Notifications” again.
   - Verify that the previously viewed notification no longer appears in the notification list.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 20:39:13 +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 a3ad4d2e00 Merge branch 'feature-payment-management-pay003' into feature-payment-management 2026-05-21 18:11:09 +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
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
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
joelthomastrenser 826919579c Merge branch 'feature-customer-management-menu' into feature-customer-management 2026-05-21 13:22:08 +05:30
joelthomastrenser 5e3b65fc5b Merge branch 'feature-customer-management-cus007' into feature-customer-management 2026-05-21 13:20:46 +05:30
joelthomastrenser ab2d41a942 Merge branch 'feature-customer-management-cus006' into feature-customer-management 2026-05-21 13:18:15 +05:30
joelthomastrenser de5311f9f9 Merge branch 'feature-customer-management-cus005' into feature-customer-management 2026-05-21 13:17:03 +05:30
joelthomastrenser 7ef7f02ee4 Merge branch 'feature-customer-management-cus004' into feature-customer-management 2026-05-21 13:12:47 +05:30
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
joelthomastrenser 5075b383d4 Merge branch 'feature-customer-management-cus003' into feature-customer-management 2026-05-21 13:07:58 +05:30
joelthomastrenser 448cb016a3 Merge branch 'feature-customer-management-cus002' into feature-customer-management 2026-05-21 13:04:35 +05:30
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 b9be43acca Implement Payment Reminder functionality
<UserStory>
NOT005: Payment Reminder
</UserStory>

<Changes>
    1. Added payment reminder check in Controller::runSystemChecks() to trigger reminder processing during system startup.
    2. Implemented PaymentManagementService::sendPaymentReminders() to identify unpaid invoices that exceed the pending payment threshold and send reminder notifications to customers.
    3. Added reminder notification logic to include invoice details and stop reminders once invoice payment status changes from Pending to Paid.
</Changes>

<Test>
    Precondition:
    1. Customer has an invoice with PaymentStatus::PENDING.
    2. Invoice age exceeds the configured payment reminder threshold.
    3. Application is started and system checks execute.

    Steps:
    1. Start the application.
    2. Allow system checks to run during startup.
    3. Navigate to View Notifications.
       - Verify that a payment reminder notification is displayed.
    4. Open the generated notification.
       - Verify that the notification includes the invoice ID and due date.
    5. Complete payment for the invoice and restart the application.
       - Verify that no further reminder notifications are generated for the paid invoice.
</Test>

<Review>
    Sreeja Reghukumar, please review
</Review>
2026-05-21 12:25:45 +05:30
joelthomastrenser aef0f4146e Implement Low Stock Alert functionality
<UserStory> NOT004: Low Stock Alert </UserStory>

<Changes>
    1. Added low stock alert check in Controller::runSystemChecks() to trigger inventory notification processing during system startup.
    2. Implemented InventoryManagementService::sendLowStockAlerts() to detect inventory items below threshold, identify admin users, and send low stock alert notifications with item details.
    3. Added helper logic to notify all admins when low stock inventory is detected.

</Changes>

<Test>

    Precondition:
    1. System has at least one admin user.
    2. Inventory item exists with quantity below the configured low stock threshold.
    3. Application is started and system checks execute.

    Steps:
    1. Start the application.
    2. Allow system checks to run during startup.
    3. Navigate to Inventory Menu / View Notifications.
       - Verify that a low stock alert notification is displayed.
    4. Open the generated notification.
       - Verify that the notification includes the part name and remaining quantity.
    5. Confirm notification content.
       - Verify that the alert was triggered only for inventory items with stock below the threshold.

</Test>

<Review>
    Sreeja Reghukumar, please review
</Review>
2026-05-21 12:20:39 +05:30
joelthomastrenser df39c0588b Implement Login functionality
<UserStory> CUS001:Login </UserStory>

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

<Test>

Login functionality validation

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

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

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 11:26:48 +05:30
joelthomastrenser 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
joelthomastrenser be306781b1 Implement Customer Menu
* Added Customer Menu display with all customer options
* Added menu choice handling using switch case
* Connected menu options to corresponding customer functions
* Added invalid choice message
* Added logout option handling
2026-05-21 10:44:42 +05:30
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
joelthomastrenser c92ad773c7 Implement Configure Notifications functionality
<UserStory> NOT006: Configure Notifications </UserStory>

<Changes>
    1. Added notification subscription configuration in CustomerMenu to allow customers to enable or disable notifications for Payment Management Service and Service Management Service.
    2. Updated Controller::configureNotifications() to attach or detach the authenticated user from service observers based on selected notification preferences.
    3. Refactored Observer interface and User notification handling to support notification delivery through observer subscriptions.
    4. Implemented observer attach, detach, and sendNotification logic in InventoryManagementService, PaymentManagementService, and ServiceManagementService to ensure notifications are sent only to subscribed users.

</Changes>

<Test>

    Precondition:
    1. Customer user is logged into the system.
    2. Notification configuration option is available in Customer Menu.
    3. Notification-triggering event exists for Payment Management Service or Service Management Service.

    Steps:
    1. Navigate to Configure Notification Preferences in Customer Menu.
    2. Enable notifications for one service and disable notifications for the other.
    3. Trigger a notification event for both services.
       - Verify that notification is received only from the subscribed service.
    4. Change preferences by disabling the subscribed service and enabling the other.
    5. Trigger notification events again.
       - Verify that notification is received only from the newly subscribed service.

</Test>

<Review>
    Sreeja Reghukumar, please review
</Review>
2026-05-20 19:55:54 +05:30
joelthomastrenser 9533a74d87 Implement Create Customer functionality
<UserStory> CUS004: Register Customer Account </UserStory>

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

<Test>

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

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

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-20 17:45:02 +05:30
joelthomastrenser 713c3b6cf9 Implement View Technician Notifications
<UserStory> NOT003: View Technician Notifications </UserStory>

<Changes>
    1. Added MenuHelper.h to the project for shared notification viewing helper support.
    2. Updated TechnicianMenu.cpp to include MenuHelper.h and route viewNotifications() through the shared notification handler.
</Changes>

<Test>

    Precondition:
    1. Technician user exists and is logged into the system.
    2. Technician has one or more notifications available.
    3. “View Notifications” option is visible in the Technician menu.

    Steps:
    1. Navigate to Technician Menu.
    2. Select “View Notifications”.
    3. Verify that the system displays a list of notifications showing title, message, and timestamp.
    4. Select a notification to view full details.
       - Verify that the selected notification is displayed and deleted after viewing.
    5. Return to the notification list or reopen “View Notifications”.
       - Verify that the previously viewed notification is no longer present.

</Test>

<Review>
    Sreeja Reghukumar, please review
</Review>
2026-05-20 16:24:34 +05:30
joelthomastrenser 1732776d13 Implement View Admin Notifications
<UserStory> NOT002: View Admin Notifications </UserStory>

<Changes>
    1. Added shared notification view handler `viewAndDeleteNotification()` in MenuHelper.h for notification viewing and deletion logic reuse.
    2. Updated AdminMenu.cpp to include MenuHelper.h and connected AdminMenu::viewNotifications() to the shared notification handler.
</Changes>

<Test>

    Precondition:
    1. Admin user exists and is logged into the system.
    2. Admin has one or more notifications available.
    3. “View Notifications” option is visible in the Admin menu.

    Steps:
    1. Navigate to Admin Menu.
    2. Select “View Notifications”.
    3. Verify that the system displays a list of notifications showing title, message, and timestamp.
    4. Select a notification to view full details.
       - Verify that the selected notification is displayed and deleted after viewing.
    5. Return to the notification list or reopen “View Notifications”.
       - Verify that the previously viewed notification is no longer present.

</Test>

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

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

</Changes>

<Test>

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

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

</Test>

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

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

<Test>

 Validate customer service booking flow and service status tracking

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

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

</Test>

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

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

<Test>

 Update Customer Profile Details

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

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

</Test>

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

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

<Test>

Change password functionality validation

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

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

</Test>

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

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

<Test>

Logout functionality validation

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

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

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-19 19:42:43 +05:30
55 changed files with 8537 additions and 580 deletions
@@ -1,7 +1,24 @@
/*
File: Trenser.VehicleServiceSystem.cpp
Description: Entry point for the Vehicle Service Management System.
Initializes the UserInterface and starts the application loop.
Author: Trenser
Date: 19-May-2026
*/
#include "UserInterface.h"
/*
Function: main
Description: The main entry point of the application.
Creates a UserInterface object and invokes the run method to start the system.
Parameters:
- None
Returns:
- int: Exit status code (0 for successful execution).
*/
int main()
{
UserInterface userInterface;
userInterface.run();
}
}
@@ -171,15 +171,21 @@
<ClInclude Include="services\PaymentManagementService.h" />
<ClInclude Include="services\ServiceManagementService.h" />
<ClInclude Include="services\UserManagementService.h" />
<ClInclude Include="utilities\Config.h" />
<ClInclude Include="utilities\Enums.h" />
<ClInclude Include="utilities\FileHelper.h" />
<ClInclude Include="utilities\FileManager.h" />
<ClInclude Include="utilities\InputHelper.h" />
<ClInclude Include="utilities\Map.h" />
<ClInclude Include="utilities\OutputHelper.h" />
<ClInclude Include="utilities\StringHelper.h" />
<ClInclude Include="utilities\Timestamp.h" />
<ClInclude Include="utilities\Utility.h" />
<ClInclude Include="utilities\Validator.h" />
<ClInclude Include="utilities\Vector.h" />
<ClInclude Include="views\AdminMenu.h" />
<ClInclude Include="views\CustomerMenu.h" />
<ClInclude Include="views\MenuHelper.h" />
<ClInclude Include="views\TechnicianMenu.h" />
<ClInclude Include="views\UserInterface.h" />
</ItemGroup>
@@ -233,5 +233,23 @@
<ClInclude Include="models\ComboPackage.h">
<Filter>Header Files\Models</Filter>
</ClInclude>
<ClInclude Include="utilities\Config.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\FileManager.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\StringHelper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\FileHelper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\Utility.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="views\MenuHelper.h">
<Filter>Header Files\Views</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -1,37 +1,113 @@
/*
File: Controller.cpp
Description: Implementation file containing the method definitions of the
Controller class, including authentication, user creation,
service purchasing, and system checks.
Author: Trenser
Date:19-May-2026
*/
#include "ComboPackage.h"
#include "Controller.h"
#include "Enums.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "JobCard.h"
#include "User.h"
#include <stdexcept>
/*
Function: login
Description: Authenticates a user by delegating to the authentication management service.
Parameter: const std::string& username - users username
const std::string& password - users password
Return type: bool - true if login successful, false otherwise
*/
bool Controller::login(const std::string& username, const std::string& password)
{
return false;
return m_authenticationManagementService.login(username, password);
}
/*
Function: logout
Description: Logs out the currently authenticated user.
Parameter: None
Return type: void
*/
void Controller::logout()
{
m_authenticationManagementService.logout();
}
/*
Function: changePassword
Description: Changes the password of the currently authenticated user.
Parameter: const std::string& newPassword - new password to set
Return type: void
*/
void Controller::changePassword(const std::string& newPassword)
{
m_authenticationManagementService.changePassword(newPassword);
}
void Controller::createCustomer(const std::string& username, const std::string& password, const std::string& email, const std::string& phone)
/*
Function: createCustomer
Description: Creates a new customer account with the provided details.
Parameter: const std::string& username - customers username
const std::string& name - customers name
const std::string& password - customers password
const std::string& email - customers email
const std::string& phone - customers phone number
Return type: void
*/
void Controller::createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone)
{
m_userManagementService.createUser(username, name, password, email, phone, util::UserType::CUSTOMER);
}
/*
Function: getAuthenticatedUser
Description: Retrieves the currently authenticated user.
Parameter: None
Return type: const User* - pointer to the authenticated user
*/
const User* Controller::getAuthenticatedUser()
{
return nullptr;
return m_authenticationManagementService.getAuthenticatedUser();
}
void Controller::createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone)
/*
Function: createTechnician
Description: Creates a new technician account with provided details by
delegating to the user management service.
Parameter: const std::string& username - technician's username
const std::string& password - technician's password
const std::string& email - technician's email address
const std::string& phoneNumber - technician's phone number
Return type: void
*/
void Controller::createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phoneNumber)
{
m_userManagementService.createUser(username, name, password, email, phoneNumber, util::UserType::TECHNICIAN);
}
/*
Function: updateUserDetails
Description: Updates the email and phone details of the currently authenticated user.
Parameter: const std::string& email - new email address
const std::string& phone - new phone number
Return type: void
*/
void Controller::updateUserDetails(const std::string& email, const std::string& phone)
{
User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (authenticatedUser == nullptr)
{
throw std::runtime_error("No user currently logged in!");
}
m_userManagementService.updateUserDetails(authenticatedUser->getId(), email, phone);
}
/*
@@ -53,36 +129,120 @@ util::Map<std::string, const Service*> Controller::getServices()
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()
{
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;
}
/*
Function: purchaseService
Description: Purchases one or more services for a vehicle by delegating to the service management service.
Parameter: const util::Vector<std::string>& serviceIDs - IDs of services to purchase
const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle
Return type: void
*/
void Controller::purchaseService(const util::Vector<std::string>& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
m_serviceManagementService.purchaseService(serviceIDs, vehicleNumber, vehicleBrand, vehicleModel);
}
/*
Function: purchaseComboPackage
Description: Purchases a combo package for a vehicle by delegating to the service management service.
Parameter: const std::string& comboPackageID - ID of the combo package
const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle
Return type: void
*/
void Controller::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel);
}
/*
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*> dummyMap;
return dummyMap;
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)
{
return nullptr;
return m_inventoryManagementService.getInventoryItem(inventoryItemID);
}
/*
Function: addInventoryItem
Description: Adds a new inventory item with specified details to the inventory management service.
Parameter: const std::string& partName - name of the part
int quantity - quantity of the part
double price - price of the part
Return type: void
*/
void Controller::addInventoryItem(const std::string& partName, int quantity, double price)
{
m_inventoryManagementService.addInventoryItem(partName, quantity, price);
}
/*
Function: removeInventoryItem
Description: Removes an inventory item from the inventory management service by its ID.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: void
*/
void Controller::removeInventoryItem(const std::string& inventoryItemID)
{
m_inventoryManagementService.removeInventoryItem(inventoryItemID);
}
/*
Function: addInventoryItemStock
Description: Adds stock to an existing inventory item in the inventory management service.
Parameter: const std::string& selectedItemId - ID of the inventory item
int quantity - quantity to add
Return type: void
*/
void Controller::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{
m_inventoryManagementService.addInventoryItemStock(selectedItemId, quantity);
}
/*
@@ -123,9 +283,22 @@ util::Map<std::string, const ServiceBooking*> Controller::getServiceBookingsByUs
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()
{
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;
}
/*
@@ -219,46 +392,258 @@ Parameters:
Returns:
- void
*/
void Controller::completeJob(const std::string& jobID)
void Controller::updateJobStatus(const std::string& jobID)
{
m_serviceManagementService.completeJob(jobID);
m_serviceManagementService.updateJobStatus(jobID);
}
/*
Function: removeUser
Description: Removes a user by ID. Cancels associated service bookings
and technician jobs before removing the user from the system.
Parameter: const std::string& userID - ID of the user to remove
Return type: void
*/
void Controller::removeUser(const std::string& userID)
{
User* user = m_userManagementService.getUser(userID);
if (!user)
{
throw std::runtime_error("Error: User not Found.\n");
}
m_userManagementService.removeUser(userID);
}
/*
Function: createComboPackage
Description: Creates a new combo package with specified services and discount
percentage by delegating to the service management service.
Parameter: const std::string& name - name of the combo package
const util::Vector<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)
{
m_serviceManagementService.createComboPackage(name, serviceIDs, discountPercentage);
}
/*
Function: removeComboPackage
Description: Removes a combo package by ID by delegating to the service
management service.
Parameter: const std::string& comboPackageID - ID of the combo package
Return type: void
*/
void Controller::removeComboPackage(const std::string& comboPackageID)
{
m_serviceManagementService.removeComboPackage(comboPackageID);
}
/*
Function: getInvoicesByUser
Description: Retrieves all invoices associated with the currently authenticated user.
Converts them into a read-only map before returning.
Parameters:
- None
Returns:
- util::Map<std::string, const Invoice*> containing the users invoices
*/
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: getAllInvoices
Description: Retrieves all invoices from the PaymentManagementService and returns them as a read-only map.
Parameters:
- none
Returns:
- util::Map<std::string, const Invoice*>: Map of invoice IDs to invoice objects
*/
util::Map<std::string, const Invoice*> Controller::getAllInvoices()
{
auto invoices = m_paymentManagementService.getAllInvoices();
util::Map<std::string, const Invoice*> readOnlyInvoice;
for (int iterator = 0; iterator < invoices.getSize(); iterator++)
{
readOnlyInvoice.insert(invoices.getKeyAt(iterator), invoices.getValueAt(iterator));
}
return readOnlyInvoice;
}
/*
Function: confirmPayment
Description: Delegates payment confirmation for a given invoice ID to the PaymentManagementService.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
*/
void Controller::confirmPayment(const std::string& invoiceID)
{
m_paymentManagementService.confirmPayment(invoiceID);
}
/*
Function: completePayment
Description: Completes payment for a specific invoice using the given payment mode.
Parameters:
- invoiceID: std::string, ID of the invoice to be paid
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
*/
void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
m_paymentManagementService.completePayment(invoiceID, paymentMode);
}
/*
Function: getNotifications
Description: Retrieves all notifications for the currently authenticated user.
Converts them into a read-only vector before returning.
Parameters: None
Return type: util::Vector<const Notification*>
*/
util::Vector<const Notification*> Controller::getNotifications()
{
return util::Vector<const Notification*>();
const User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (!authenticatedUser)
{
throw std::runtime_error("No user is currently logged in!");
}
auto notifications = m_userManagementService.getUserNotifications(authenticatedUser->getId());
int numberOfNotifications = notifications.getSize();
util::Vector<const Notification*> readOnlyNotifications;
for (int index = 0; index < numberOfNotifications; index++)
{
readOnlyNotifications.push_back(notifications[index]);
}
return readOnlyNotifications;
}
/*
Function: deleteNotification
Description: Deletes a specific notification for the currently authenticated user.
Parameters:
- notificationID: std::string, the unique identifier of the notification
Return type: void
*/
void Controller::deleteNotification(const std::string& notificationID)
{
const User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (!authenticatedUser)
{
throw std::runtime_error("No user is currently logged in!");
}
m_userManagementService.deleteNotification(notificationID, authenticatedUser->getId());
}
void Controller::configureNotifications(const std::string& userID, bool paymentNotifications, bool serviceNotifications)
/*
Function: configureNotifications
Description: Configures notification preferences for the authenticated user.
Attaches or detaches the user from payment and service notifications.
Parameters:
- paymentNotifications: bool, enable/disable payment notifications
- serviceNotifications: bool, enable/disable service notifications
Return type: void
*/
void Controller::configureNotifications(bool paymentNotifications, bool serviceNotifications)
{
User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (authenticatedUser)
{
if (paymentNotifications)
{
m_paymentManagementService.attach(authenticatedUser);
}
else
{
m_paymentManagementService.detach(authenticatedUser);
}
if (serviceNotifications)
{
m_serviceManagementService.attach(authenticatedUser);
}
else
{
m_serviceManagementService.detach(authenticatedUser);
}
}
else
{
throw std::runtime_error("No user is currently logged in!");
}
}
/*
Function: loadSystemData
Description: Loads all system data from persistent storage into memory.
Invokes the respective management services to load users, inventory items, services,
combo packages, service bookings, job cards, invoices, and observers.
Parameters:
- None
Returns:
- void
*/
void Controller::loadSystemData()
{
m_userManagementService.loadUsers();
m_inventoryManagementService.loadInventoryItems();
m_serviceManagementService.loadServices();
m_serviceManagementService.loadComboPackages();
m_serviceManagementService.loadServiceBookings();
m_serviceManagementService.loadJobCards();
m_paymentManagementService.loadInvoices();
m_serviceManagementService.loadObservers();
m_paymentManagementService.loadObservers();
m_inventoryManagementService.loadObservers();
}
/*
Function: saveSystemData
Description: Saves all system data from memory back to persistent storage.
Invokes the respective management services to save users, inventory items, services,
combo packages, service bookings, job cards, invoices, and observers.
Parameters:
- None
Returns:
- void
*/
void Controller::saveSystemData()
{
m_userManagementService.saveUsers();
m_inventoryManagementService.saveInventoryItems();
m_serviceManagementService.saveServices();
m_serviceManagementService.saveComboPackages();
m_serviceManagementService.saveServiceBookings();
m_serviceManagementService.saveJobCards();
m_paymentManagementService.saveInvoices();
m_serviceManagementService.saveObservers();
m_paymentManagementService.saveObservers();
m_inventoryManagementService.saveObservers();
}
/*
Function: runSystemChecks
Description: Runs system checks to ensure critical configurations, such as verifying admin existence.
Parameter: None
Return type: void
*/
void Controller::runSystemChecks()
{
m_userManagementService.ensureAdminExists();
m_inventoryManagementService.sendLowStockAlerts();
m_paymentManagementService.sendPaymentReminders();
}
@@ -1,10 +1,21 @@
/*
File: Controller.h
Description: Header file declaring the Controller class, which manages
user authentication, inventory, services, bookings, job cards,
invoices, and notifications in the system.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Map.h"
#include <string>
#include "AuthenticationManagementService.h"
#include "Enums.h"
#include "InventoryManagementService.h"
#include "Map.h"
#include "PaymentManagementService.h"
#include "ServiceManagementService.h"
#include "UserManagementService.h"
#include "InventoryManagementService.h"
class Service;
class ComboPackage;
@@ -18,15 +29,18 @@ class Notification;
class Controller
{
private:
ServiceManagementService m_serviceManagementService;
AuthenticationManagementService m_authenticationManagementService;
UserManagementService m_userManagementService;
ServiceManagementService m_serviceManagementService;
InventoryManagementService m_inventoryManagementService;
PaymentManagementService m_paymentManagementService;
public:
bool login(const std::string& username, const std::string& password);
void logout();
void changePassword(const std::string& newPassword);
void createCustomer(const std::string& username, const std::string& password, const std::string& email, const std::string& phone);
void createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone);
const User* getAuthenticatedUser();
void createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone);
void createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone);
void updateUserDetails(const std::string& email, const std::string& phone);
util::Map<std::string, const Service*> getServices();
util::Map<std::string, const ComboPackage*> getComboPackages();
@@ -35,6 +49,7 @@ public:
util::Map<std::string, const InventoryItem*> getInventoryItems();
const InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void removeInventoryItem(const std::string& inventoryItemID);
util::Map<std::string, const ServiceBooking*> getServiceBookings();
util::Map<std::string, const ServiceBooking*> getServiceBookingsByUser(const std::string userID);
@@ -44,14 +59,18 @@ public:
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID);
util::Map<std::string, const JobCard*> getJobCardsByUser();
void completeJob(const std::string& jobID);
void updateJobStatus(const std::string& jobID);
void removeUser(const std::string& userID);
void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage);
void removeComboPackage(const std::string& comboPackageID);
util::Map<std::string, const Invoice*> getInvoicesByUser();
util::Map<std::string, const Invoice*> getAllInvoices();
void confirmPayment(const std::string& invoiceID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
util::Vector<const Notification*> getNotifications();
void deleteNotification(const std::string& notificationID);
void configureNotifications(const std::string& userID, bool paymentNotifications, bool serviceNotifications);
void configureNotifications(bool paymentNotifications, bool serviceNotifications);
void loadSystemData();
void saveSystemData();
void runSystemChecks();
};
@@ -1,3 +1,10 @@
/*
File: Observer.h
Description: Declares the Observer interface for handling notifications in the Vehicle Service Management System.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
class Notification;
@@ -6,5 +13,5 @@ class Observer
{
public:
virtual ~Observer() = default;
virtual void update(Notification* notification) = 0;
virtual void addNotification(Notification* notification) = 0;
};
@@ -1,6 +1,14 @@
/*
File: Subject.h
Description: Declares the Subject interface for managing user attachments and detachments in the Observer design pattern within the Vehicle Service Management System.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
class User;
class Notification;
@@ -1,46 +1,128 @@
/*
File: DataStore.cpp
Description: Implements the DataStore class which provides a centralized singleton repository
for managing system data in the Vehicle Service Management System.
Includes accessors for users, services, combo packages, service bookings,
job cards, inventory items, invoices, and payments.
Author: Trenser
Date: 19-May-2026
*/
#include "DataStore.h"
/*
Function: getInstance
Description: Provides a singleton instance of the DataStore class.
Parameters:
- None
Returns:
- Reference to the single DataStore instance.
*/
DataStore& DataStore::getInstance()
{
static DataStore dataStore;
return dataStore;
}
/*
Function: getUsers
Description: Retrieves the internal map of users.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, User*> containing all users.
*/
util::Map<std::string, User*>& DataStore::getUsers()
{
return m_users;
}
/*
Function: getServices
Description: Retrieves the internal map of services.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, Service*> containing all services.
*/
util::Map<std::string, Service*>& DataStore::getServices()
{
return m_services;
}
/*
Function: getComboPackages
Description: Retrieves the internal map of combo packages.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, ComboPackage*> containing all combo packages.
*/
util::Map<std::string, ComboPackage*>& DataStore::getComboPackages()
{
return m_comboPackages;
}
/*
Function: getServiceBookings
Description: Retrieves the internal map of service bookings.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, ServiceBooking*> containing all service bookings.
*/
util::Map<std::string, ServiceBooking*>& DataStore::getServiceBookings()
{
return m_serviceBookings;
}
/*
Function: getJobCards
Description: Retrieves the internal map of job cards.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, JobCard*> containing all job cards.
*/
util::Map<std::string, JobCard*>& DataStore::getJobCards()
{
return m_jobCards;
}
/*
Function: getInventoryItems
Description: Retrieves the internal map of inventory items.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, InventoryItem*> containing all inventory items.
*/
util::Map<std::string, InventoryItem*>& DataStore::getInventoryItems()
{
return m_inventoryItems;
}
/*
Function: getInvoices
Description: Retrieves the internal map of invoices.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, Invoice*> containing all invoices.
*/
util::Map<std::string, Invoice*>& DataStore::getInvoices()
{
return m_invoices;
}
/*
Function: getPayments
Description: Retrieves the internal map of payments.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, Payment*> containing all payments.
*/
util::Map<std::string, Payment*>& DataStore::getPayments()
{
return m_payments;
@@ -1,5 +1,11 @@
#pragma once
/*
File: DataStore.h
Description: Declares the DataStore singleton class responsible for managing collections of users, services, combo packages, service bookings, job cards, inventory items, invoices, and payments in the Vehicle Service Management System.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
@@ -1,65 +1,341 @@
/*
File: ComboPackage.cpp
Description: Implements the ComboPackage class which represents a bundled set of services in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for package details such as ID, name, discount percentage, state,
and associated services.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include <stdexcept>
#include "ComboPackage.h"
#include "Service.h"
#include "Factory.h"
#include "StringHelper.h"
int ComboPackage::m_uid = 0;
/*
Function: ComboPackage
Description: Default constructor that initializes a new combo package with a unique ID,
active state, and zero discount percentage.
Parameters:
- None
Returns:
- A new ComboPackage object.
*/
ComboPackage::ComboPackage()
: m_id("CMP" + std::to_string(++m_uid)),
m_status(util::State::ACTIVE),
m_discountPercentage(0.0) {}
/*
Function: ComboPackage
Description: Parameterized constructor that initializes a new combo package with a unique ID,
specified package name, discount percentage, active state, and associated services.
Parameters:
- packageName: Name of the combo package.
- discountPercentage: Discount percentage applied to the package.
- services: Map of services included in the package.
Returns:
- A new ComboPackage object.
*/
ComboPackage::ComboPackage(const std::string& packageName, double discountPercentage, const util::Map<std::string, Service*>& services)
: m_id("CMP" + std::to_string(++m_uid)),
m_packageName(packageName),
m_discountPercentage(discountPercentage),
m_status(util::State::ACTIVE),
m_services(services) {}
m_services(services)
{
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
/*
Function: ComboPackage (parameterized constructor with ID)
Description: Initializes a combo package with an existing ID, name, discount percentage,
service IDs, and state. Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique ID of the package
- packageName: const std::string&, name of the package
- discountPercentage: double, discount percentage applied
- serviceIDs: const util::Vector<std::string>&, IDs of services included
- status: util::State, state of the package (ACTIVE/INACTIVE)
Returns:
- A new ComboPackage object
*/
ComboPackage::ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector<std::string>& serviceIDs, util::State status)
: m_id(id),
m_packageName(packageName),
m_discountPercentage(discountPercentage),
m_serviceIDs(serviceIDs),
m_status(status)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the combo package.
Parameters:
- None
Returns:
- const std::string& representing the package ID.
*/
const std::string& ComboPackage::getId() const
{
return m_id;
}
/*
Function: getPackageName
Description: Retrieves the name of the combo package.
Parameters:
- None
Returns:
- const std::string& representing the package name.
*/
const std::string& ComboPackage::getPackageName() const
{
return m_packageName;
}
/*
Function: getDiscountPercentage
Description: Retrieves the discount percentage applied to the combo package.
Parameters:
- None
Returns:
- double representing the discount percentage.
*/
double ComboPackage::getDiscountPercentage() const
{
return m_discountPercentage;
}
/*
Function: getState
Description: Retrieves the current state (ACTIVE/INACTIVE) of the combo package.
Parameters:
- None
Returns:
- util::State representing the package state.
*/
util::State ComboPackage::getState() const
{
return m_status;
}
const util::Vector<std::string>& ComboPackage::getServiceIDs() const
{
return m_serviceIDs;
}
/*
Function: getServices
Description: Retrieves the map of services included in the combo package.
Parameters:
- None
Returns:
- const util::Map<std::string, Service*>& representing the services.
*/
const util::Map<std::string, Service*>& ComboPackage::getServices() const
{
return m_services;
}
/*
Function: setId
Description: Sets the unique ID of the combo package.
Parameters:
- id: New ID string.
Returns:
- void
*/
void ComboPackage::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setPackageName
Description: Sets the name of the combo package.
Parameters:
- packageName: New package name string.
Returns:
- void
*/
void ComboPackage::setPackageName(const std::string& packageName)
{
m_packageName = packageName;
}
/*
Function: setDiscountPercentage
Description: Sets the discount percentage for the combo package.
Parameters:
- discountPercentage: New discount percentage value.
Returns:
- void
*/
void ComboPackage::setDiscountPercentage(double discountPercentage)
{
m_discountPercentage = discountPercentage;
}
/*
Function: setServices
Description: Sets the services included in the combo package.
Parameters:
- services: Map of services to be associated with the package.
Returns:
- void
*/
void ComboPackage::setServices(const util::Map<std::string, Service*>& services)
{
m_services = services;
m_serviceIDs.clear();
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
/*
Function: setState
Description: Sets the state (ACTIVE/INACTIVE) of the combo package.
Parameters:
- status: New state value.
Returns:
- void
*/
void ComboPackage::setState(util::State status)
{
m_status = status;
}
/*
Function: getServiceIDsAsString (static helper)
Description: Converts a vector of service IDs into a single string separated by '|'.
Parameters:
- serviceIDs: const util::Vector<std::string>&, vector of service IDs
Returns:
- std::string: Concatenated service IDs string
*/
static std::string getServiceIDsAsString(const util::Vector<std::string>& serviceIDs)
{
int numberOfServices = serviceIDs.getSize();
std::string serviceIDsString;
for (int index = 0; index < numberOfServices; index++)
{
serviceIDsString += serviceIDs[index];
if (index < numberOfServices - 1)
{
serviceIDsString += '|';
}
}
return serviceIDsString;
}
/*
Function: getServiceIDsAsVector (static helper)
Description: Converts a string of service IDs separated by '|' into a vector.
Parameters:
- serviceIDsString: const std::string&, concatenated service IDs string
Returns:
- util::Vector<std::string>: Vector of service IDs
*/
static util::Vector<std::string> getServiceIDsAsVector(const std::string& serviceIDsString)
{
util::Vector<std::string> serviceIDs;
std::string serviceID;
std::istringstream serializedServiceIDs(serviceIDsString);
while (getline(serializedServiceIDs, serviceID, '|'))
{
serviceIDs.push_back(serviceID);
}
return serviceIDs;
}
/*
Function: serialize
Description: Serializes the combo package into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized combo package record
*/
std::string ComboPackage::serialize() const
{
std::ostringstream serializedComboPackage;
serializedComboPackage << m_id << ','
<< m_packageName << ','
<< m_discountPercentage << ','
<< getServiceIDsAsString(m_serviceIDs) << ','
<< util::getStateString(m_status);
return serializedComboPackage.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a ComboPackage object.
Parameters:
- record: const std::string&, serialized combo package record
Returns:
- ComboPackage*: Pointer to the deserialized ComboPackage object
Throws:
- std::runtime_error if data is invalid
*/
ComboPackage* ComboPackage::deserialize(const std::string& record)
{
std::string id, packageName;
std::string discountPercentageString, serviceIDsString, statusString;
double discountPercentage;
std::istringstream serializedComboPackage(record);
getline(serializedComboPackage, id, ',');
getline(serializedComboPackage, packageName, ',');
getline(serializedComboPackage, discountPercentageString, ',');
getline(serializedComboPackage, serviceIDsString, ',');
getline(serializedComboPackage, statusString, ',');
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid combo package data");
}
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
util::State status = util::getState(statusString);
return Factory::getObject<ComboPackage>(
id,
packageName,
discountPercentage,
serviceIDs,
status
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for combo package serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,PackageName,DiscountPercentage,ServiceIDs,Status")
*/
std::string ComboPackage::getHeaders()
{
return "ID,PackageName,DiscountPercentage,ServiceIDs,Status";
}
@@ -1,6 +1,14 @@
/*
File: ComboPackage.h
Description: Declares the ComboPackage class which represents a service package with a unique ID, package name, discount percentage, associated services, and status in the Vehicle Service Management System.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
#include "Enums.h"
class Service;
@@ -12,14 +20,17 @@ private:
std::string m_id;
std::string m_packageName;
double m_discountPercentage;
util::Vector<std::string> m_serviceIDs;
util::Map<std::string, Service*> m_services;
util::State m_status;
public:
ComboPackage();
ComboPackage(const std::string& packageName, double discountPercentage, const util::Map<std::string, Service*>& services);
ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector<std::string>& serviceIDs, util::State status);
const std::string& getId() const;
const std::string& getPackageName() const;
double getDiscountPercentage() const;
const util::Vector<std::string>& getServiceIDs() const;
const util::Map<std::string, Service*>& getServices() const;
util::State getState() const;
void setId(const std::string& id);
@@ -27,4 +38,7 @@ public:
void setDiscountPercentage(double discountPercentage);
void setServices(const util::Map<std::string, Service*>& services);
void setState(util::State status);
std::string serialize() const;
static ComboPackage* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,13 +1,45 @@
/*
File: InventoryItem.cpp
Description: Implements the InventoryItem class which represents an inventory item in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for item details such as ID, part name, quantity, price, and state.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include <stdexcept>
#include "Factory.h"
#include "StringHelper.h"
#include "InventoryItem.h"
int InventoryItem::m_uid = 0;
/*
Function: InventoryItem
Description: Default constructor that initializes a new inventory item with a unique ID,
active state, zero quantity, and zero price.
Parameters:
- None
Returns:
- A new InventoryItem object.
*/
InventoryItem::InventoryItem()
: m_id("IIM" + std::to_string(++m_uid)),
m_quantity(0),
m_status(util::State::ACTIVE),
m_price(0.0) {}
/*
Function: InventoryItem
Description: Parameterized constructor that initializes a new inventory item with a unique ID,
specified part name, quantity, price, and active state.
Parameters:
- partName: Name of the inventory item.
- quantity: Initial quantity of the item.
- price: Price of the item.
Returns:
- A new InventoryItem object.
*/
InventoryItem::InventoryItem(const std::string& partName, int quantity, double price)
: m_id("IIM" + std::to_string(++m_uid)),
m_partName(partName),
@@ -15,52 +47,232 @@ InventoryItem::InventoryItem(const std::string& partName, int quantity, double p
m_status(util::State::ACTIVE),
m_price(price) {}
/*
Function: InventoryItem (parameterized constructor with ID)
Description: Initializes an inventory item with an existing ID, part name, quantity,
price, and state. Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique ID of the item
- partName: const std::string&, name of the part
- quantity: int, quantity of the part
- price: double, price of the part
- status: util::State, state of the item (ACTIVE/INACTIVE)
Returns:
- A new InventoryItem object
*/
InventoryItem::InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status)
: m_id(id),
m_partName(partName),
m_quantity(quantity),
m_status(status),
m_price(price)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the inventory item.
Parameters:
- None
Returns:
- const std::string& representing the item ID.
*/
const std::string& InventoryItem::getId() const
{
return m_id;
}
/*
Function: getPartName
Description: Retrieves the part name of the inventory item.
Parameters:
- None
Returns:
- const std::string& representing the part name.
*/
const std::string& InventoryItem::getPartName() const
{
return m_partName;
}
/*
Function: getQuantity
Description: Retrieves the current quantity of the inventory item.
Parameters:
- None
Returns:
- int representing the quantity.
*/
int InventoryItem::getQuantity() const
{
return m_quantity;
}
/*
Function: getPrice
Description: Retrieves the price of the inventory item.
Parameters:
- None
Returns:
- double representing the price.
*/
double InventoryItem::getPrice() const
{
return m_price;
}
/*
Function: getState
Description: Retrieves the current state (ACTIVE/INACTIVE) of the inventory item.
Parameters:
- None
Returns:
- util::State representing the item state.
*/
util::State InventoryItem::getState() const
{
return m_status;
}
/*
Function: setId
Description: Sets the unique ID of the inventory item.
Parameters:
- id: New ID string.
Returns:
- void
*/
void InventoryItem::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setPartName
Description: Sets the part name of the inventory item.
Parameters:
- partName: New part name string.
Returns:
- void
*/
void InventoryItem::setPartName(const std::string& partName)
{
m_partName = partName;
}
/*
Function: setQuantity
Description: Sets the quantity of the inventory item.
Parameters:
- quantity: New quantity value.
Returns:
- void
*/
void InventoryItem::setQuantity(int quantity)
{
m_quantity = quantity;
}
/*
Function: setPrice
Description: Sets the price of the inventory item.
Parameters:
- price: New price value.
Returns:
- void
*/
void InventoryItem::setPrice(double price)
{
m_price = price;
}
/*
Function: setState
Description: Sets the state (ACTIVE/INACTIVE) of the inventory item.
Parameters:
- status: New state value.
Returns:
- void
*/
void InventoryItem::setState(util::State status)
{
m_status = status;
}
/*
Function: serialize
Description: Serializes the inventory item into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized inventory item record
*/
std::string InventoryItem::serialize() const
{
std::ostringstream serializedInventoryItem;
serializedInventoryItem << m_id << ','
<< m_partName << ','
<< m_quantity << ','
<< m_price << ','
<< util::getStateString(m_status);
return serializedInventoryItem.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into an InventoryItem object.
Parameters:
- record: const std::string&, serialized inventory item record
Returns:
- InventoryItem*: Pointer to the deserialized InventoryItem object
Throws:
- std::runtime_error if data is invalid
*/
InventoryItem* InventoryItem::deserialize(const std::string& record)
{
std::string id, partName;
std::string quantityString, priceString, statusString;
int quantity;
double price;
std::istringstream serializedInventoryItem(record);
getline(serializedInventoryItem, id, ',');
getline(serializedInventoryItem, partName, ',');
getline(serializedInventoryItem, quantityString, ',');
getline(serializedInventoryItem, priceString, ',');
getline(serializedInventoryItem, statusString, ',');
try
{
quantity = std::stoi(quantityString);
price = std::stod(priceString);
}
catch (...)
{
throw std::runtime_error("Invalid inventory item data");
}
util::State status = util::getState(statusString);
return Factory::getObject<InventoryItem>(
id,
partName,
quantity,
price,
status
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for inventory item serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,PartName,Quantity,Price,Status")
*/
std::string InventoryItem::getHeaders()
{
return "ID,PartName,Quantity,Price,Status";
}
@@ -1,3 +1,12 @@
/*
File: InventoryItem.h
Description: Declares the InventoryItem class which represents parts in the Vehicle Service Management System.
Each item has a unique ID, part name, quantity, price, and status.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Enums.h"
@@ -14,6 +23,7 @@ private:
public:
InventoryItem();
InventoryItem(const std::string& partName, int quantity, double price);
InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status);
const std::string& getId() const;
const std::string& getPartName() const;
int getQuantity() const;
@@ -24,4 +34,7 @@ public:
void setQuantity(int quantity);
void setPrice(double price);
void setState(util::State status);
std::string serialize() const;
static InventoryItem* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,7 +1,31 @@
/*
File: Invoice.cpp
Description: Implements the Invoice class which represents an invoice in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for invoice details such as ID, booking, costs,
discount percentage, total amount, payment details, and status.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include <stdexcept>
#include "Invoice.h"
#include "Factory.h"
#include "InventoryItem.h"
#include "StringHelper.h"
int Invoice::m_uid = 0;
/*
Function: Invoice
Description: Default constructor that initializes a new invoice with a unique ID,
null booking, zero costs, zero discount, zero total amount,
and default payment method and status.
Parameters:
- None
Returns:
- A new Invoice object.
*/
Invoice::Invoice()
: m_id("INV" + std::to_string(++m_uid)),
m_booking(nullptr),
@@ -12,12 +36,30 @@ Invoice::Invoice()
m_paymentMethod(util::PaymentMode()),
m_status(util::PaymentStatus()) {}
/*
Function: Invoice
Description: Parameterized constructor that initializes a new invoice with a unique ID and specified details.
Parameters:
- bookingId: ID of the associated service booking.
- booking: Pointer to the ServiceBooking object.
- invoiceDate: Timestamp of when the invoice was created.
- laborCost: Cost of labor for the service.
- parts: Map of inventory items used in the service.
- partsCost: Total cost of parts.
- discountPercentage: Discount applied to the invoice.
- totalAmount: Final total amount after discount.
- paymentDate: Timestamp of when payment was made.
- paymentMethod: Payment mode (ONLINE/OFFLINE).
- status: Payment status (PENDING/COMPLETED).
Returns:
- A new Invoice object.
*/
Invoice::Invoice(
const std::string& bookingId,
ServiceBooking* booking,
const util::Timestamp& invoiceDate,
double laborCost, const util::Map<int,
InventoryItem*>& parts,
double laborCost,
const util::Map<std::string, InventoryItem*>& parts,
double partsCost,
double discountPercentage,
double totalAmount,
@@ -36,124 +78,495 @@ Invoice::Invoice(
m_totalAmount(totalAmount),
m_paymentDate(paymentDate),
m_paymentMethod(paymentMethod),
m_status(status) {}
m_status(status)
{
int numberOfParts = m_parts.getSize();
auto partPointers = m_parts.getValues();
for (int index = 0; index < numberOfParts; index++)
{
m_partIDs.push_back(partPointers[index]->getId());
}
}
Invoice::Invoice(
const std::string& id,
const std::string& bookingId,
const util::Timestamp& invoiceDate,
const util::Vector<std::string>& partIDs,
double laborCost,
double partsCost,
double discountPercentage,
double totalAmount,
const util::Timestamp& paymentDate,
util::PaymentMode paymentMethod,
util::PaymentStatus status
)
: m_id(id),
m_bookingId(bookingId),
m_booking(nullptr),
m_invoiceDate(invoiceDate),
m_partIDs(partIDs),
m_laborCost(laborCost),
m_partsCost(partsCost),
m_discountPercentage(discountPercentage),
m_totalAmount(totalAmount),
m_paymentDate(paymentDate),
m_paymentMethod(paymentMethod),
m_status(status)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the invoice.
Returns:
- const std::string& representing the invoice ID.
*/
const std::string& Invoice::getId() const
{
return m_id;
}
/*
Function: getBookingId
Description: Retrieves the booking ID associated with the invoice.
Returns:
- const std::string& representing the booking ID.
*/
const std::string& Invoice::getBookingId() const
{
return m_bookingId;
}
/*
Function: getBooking
Description: Retrieves the pointer to the associated ServiceBooking.
Returns:
- ServiceBooking* representing the booking.
*/
ServiceBooking* Invoice::getBooking() const
{
return m_booking;
}
/*
Function: getInvoiceDate
Description: Retrieves the timestamp of the invoice creation date.
Returns:
- const util::Timestamp& representing the invoice date.
*/
const util::Timestamp& Invoice::getInvoiceDate() const
{
return m_invoiceDate;
}
/*
Function: getLaborCost
Description: Retrieves the labor cost associated with the invoice.
Returns:
- double representing the labor cost.
*/
double Invoice::getLaborCost() const
{
return m_laborCost;
}
const util::Map<int, InventoryItem*>& Invoice::getParts() const
/*
Function: getPartIDs
Description: Retrieves the IDs of parts used in the invoice.
Parameters:
- None
Returns:
- const util::Vector<std::string>&: Part IDs
*/
const util::Vector<std::string>& Invoice::getPartIDs() const
{
return m_partIDs;
}
/*
Function: getParts
Description: Retrieves the map of inventory items used in the service.
Returns:
- const util::Map<int, InventoryItem*>& representing the parts.
*/
const util::Map<std::string, InventoryItem*>& Invoice::getParts() const
{
return m_parts;
}
/*
Function: getPartsCost
Description: Retrieves the total cost of parts used in the service.
Returns:
- double representing the parts cost.
*/
double Invoice::getPartsCost() const
{
return m_partsCost;
}
/*
Function: getDiscountPercentage
Description: Retrieves the discount percentage applied to the invoice.
Returns:
- double representing the discount percentage.
*/
double Invoice::getDiscountPercentage() const
{
return m_discountPercentage;
}
/*
Function: getTotalAmount
Description: Retrieves the total amount of the invoice after discount.
Returns:
- double representing the total amount.
*/
double Invoice::getTotalAmount() const
{
return m_totalAmount;
}
/*
Function: getPaymentDate
Description: Retrieves the timestamp of the payment date.
Returns:
- const util::Timestamp& representing the payment date.
*/
const util::Timestamp& Invoice::getPaymentDate() const
{
return m_paymentDate;
}
/*
Function: getPaymentMethod
Description: Retrieves the payment mode used for the invoice.
Returns:
- util::PaymentMode representing the payment method.
*/
util::PaymentMode Invoice::getPaymentMethod() const
{
return m_paymentMethod;
}
/*
Function: getStatus
Description: Retrieves the payment status of the invoice.
Returns:
- util::PaymentStatus representing the payment status.
*/
util::PaymentStatus Invoice::getStatus() const
{
return m_status;
}
/*
Function: setId
Description: Sets the unique ID of the invoice.
Parameters:
- id: New invoice ID string.
Returns:
- void
*/
void Invoice::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setBookingId
Description: Sets the booking ID associated with the invoice.
Parameters:
- bookingId: New booking ID string.
Returns:
- void
*/
void Invoice::setBookingId(const std::string& bookingId)
{
m_bookingId = bookingId;
}
/*
Function: setBooking
Description: Sets the associated ServiceBooking pointer.
Parameters:
- booking: Pointer to the ServiceBooking object.
Returns:
- void
*/
void Invoice::setBooking(ServiceBooking* booking)
{
m_booking = booking;
}
/*
Function: setInvoiceDate
Description: Sets the invoice creation date.
Parameters:
- invoiceDate: New timestamp for the invoice date.
Returns:
- void
*/
void Invoice::setInvoiceDate(const util::Timestamp& invoiceDate)
{
m_invoiceDate = invoiceDate;
}
/*
Function: setLaborCost
Description: Sets the labor cost for the invoice.
Parameters:
- laborCost: New labor cost value.
Returns:
- void
*/
void Invoice::setLaborCost(double laborCost)
{
m_laborCost = laborCost;
}
void Invoice::setParts(const util::Map<int, InventoryItem*>& parts)
/*
Function: setParts
Description: Sets the inventory items used in the service.
Parameters:
- parts: Map of inventory items.
Returns:
- void
*/
void Invoice::setParts(const util::Map<std::string, InventoryItem*>& parts)
{
m_parts = parts;
m_partIDs.clear();
int numberOfParts = m_parts.getSize();
auto partPointers = m_parts.getValues();
for (int index = 0; index < numberOfParts; index++)
{
m_partIDs.push_back(partPointers[index]->getId());
}
}
/*
Function: setPartsCost
Description: Sets the total cost of parts used in the service.
Parameters:
- partsCost: New parts cost value.
Returns:
- void
*/
void Invoice::setPartsCost(double partsCost)
{
m_partsCost = partsCost;
}
/*
Function: setDiscountPercentage
Description: Sets the discount percentage applied to the invoice.
Parameters:
- discountPercentage: New discount percentage value.
Returns:
- void
*/
void Invoice::setDiscountPercentage(double discountPercentage)
{
m_discountPercentage = discountPercentage;
}
/*
Function: setTotalAmount
Description: Sets the total amount of the invoice.
Parameters:
- totalAmount: New total amount value.
Returns:
- void
*/
void Invoice::setTotalAmount(double totalAmount)
{
m_totalAmount = totalAmount;
}
/*
Function: setPaymentDate
Description: Sets the payment date for the invoice.
Parameters:
- paymentDate: New timestamp for the payment date.
Returns:
- void
*/
void Invoice::setPaymentDate(const util::Timestamp& paymentDate)
{
m_paymentDate = paymentDate;
}
/*
Function: setPaymentMethod
Description: Sets the payment mode for the invoice.
Parameters:
- paymentMethod: New payment mode value.
Returns:
- void
*/
void Invoice::setPaymentMethod(util::PaymentMode paymentMethod)
{
m_paymentMethod = paymentMethod;
}
/*
Function: setStatus
Description: Sets the payment status of the invoice.
Parameters:
- status: New payment status value.
Returns:
- void
*/
void Invoice::setStatus(util::PaymentStatus status)
{
m_status = status;
}
/*
Function: getPartIDsAsString (static helper)
Description: Converts a vector of part IDs into a single string separated by '|'.
Parameters:
- partIDs: const util::Vector<std::string>&, vector of part IDs
Returns:
- std::string: Concatenated part IDs string
*/
static std::string getPartIDsAsString(const util::Vector<std::string>& partIDs)
{
int numberOfParts = partIDs.getSize();
std::string partIDsString;
for (int index = 0; index < numberOfParts; index++)
{
partIDsString += partIDs[index];
if (index < numberOfParts - 1)
{
partIDsString += '|';
}
}
return partIDsString;
}
/*
Function: getPartIDsAsVector (static helper)
Description: Converts a string of part IDs separated by '|' into a vector.
Parameters:
- partIDsString: const std::string&, concatenated part IDs string
Returns:
- util::Vector<std::string>: Vector of part IDs
*/
static util::Vector<std::string> getPartIDsAsVector(const std::string& partIDsString)
{
util::Vector<std::string> partIDs;
std::string partID;
std::istringstream serializedPartIDs(partIDsString);
while (getline(serializedPartIDs, partID, '|'))
{
partIDs.push_back(partID);
}
return partIDs;
}
/*
Function: serialize
Description: Serializes the invoice into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized invoice record
*/
std::string Invoice::serialize() const
{
std::ostringstream serializedInvoice;
serializedInvoice << m_id << ','
<< m_bookingId << ','
<< m_invoiceDate.toString() << ','
<< m_laborCost << ','
<< getPartIDsAsString(m_partIDs) << ','
<< m_partsCost << ','
<< m_discountPercentage << ','
<< m_totalAmount << ','
<< m_paymentDate.toString() << ','
<< util::getPaymentModeString(m_paymentMethod) << ','
<< util::getPaymentStatusString(m_status);
return serializedInvoice.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into an Invoice object.
Parameters:
- record: const std::string&, serialized invoice record
Returns:
- Invoice*: Pointer to the deserialized Invoice object
Throws:
- std::runtime_error if data is invalid
*/
Invoice* Invoice::deserialize(const std::string& record)
{
std::string id, bookingId;
std::string invoiceDateString, laborCostString, partIDsString;
std::string partsCostString, discountPercentageString, totalAmountString;
std::string paymentDateString, paymentMethodString, statusString;
double laborCost, partsCost, discountPercentage, totalAmount;
std::istringstream serializedInvoice(record);
getline(serializedInvoice, id, ',');
getline(serializedInvoice, bookingId, ',');
getline(serializedInvoice, invoiceDateString, ',');
getline(serializedInvoice, laborCostString, ',');
getline(serializedInvoice, partIDsString, ',');
getline(serializedInvoice, partsCostString, ',');
getline(serializedInvoice, discountPercentageString, ',');
getline(serializedInvoice, totalAmountString, ',');
getline(serializedInvoice, paymentDateString, ',');
getline(serializedInvoice, paymentMethodString, ',');
getline(serializedInvoice, statusString, ',');
util::Timestamp invoiceDate;
util::Timestamp paymentDate;
try
{
invoiceDate = util::Timestamp::fromString(invoiceDateString);
paymentDate = util::Timestamp::fromString(paymentDateString);
laborCost = std::stod(laborCostString);
partsCost = std::stod(partsCostString);
discountPercentage = std::stod(discountPercentageString);
totalAmount = std::stod(totalAmountString);
}
catch (...)
{
throw std::runtime_error("Invalid invoice data");
}
util::Vector<std::string> partIDs = getPartIDsAsVector(partIDsString);
util::PaymentMode paymentMethod = util::getPaymentMode(paymentMethodString);
util::PaymentStatus status = util::getPaymentStatus(statusString);
return Factory::getObject<Invoice>(
id,
bookingId,
invoiceDate,
partIDs,
laborCost,
partsCost,
discountPercentage,
totalAmount,
paymentDate,
paymentMethod,
status
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for invoice serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status")
*/
std::string Invoice::getHeaders()
{
return "ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status";
}
@@ -1,6 +1,16 @@
/*
File: Invoice.h
Description: Declares the Invoice class which represents billing details for a service booking in the Vehicle Service Management System.
Each invoice includes booking information, labor cost, parts used, discount percentage, total amount, payment details, and status.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
#include "Timestamp.h"
#include "Enums.h"
@@ -16,22 +26,22 @@ private:
ServiceBooking* m_booking;
util::Timestamp m_invoiceDate;
double m_laborCost;
util::Map<int, InventoryItem*> m_parts;
util::Vector<std::string> m_partIDs;
util::Map<std::string, InventoryItem*> m_parts;
double m_partsCost;
double m_discountPercentage;
double m_totalAmount;
util::Timestamp m_paymentDate;
util::PaymentMode m_paymentMethod;
util::PaymentStatus m_status;
public:
Invoice();
Invoice(
const std::string& bookingId,
ServiceBooking* booking,
const util::Timestamp& invoiceDate,
double laborCost, const util::Map<int,
InventoryItem*>& parts,
double laborCost,
const util::Map<std::string,InventoryItem*>& parts,
double partsCost,
double discountPercentage,
double totalAmount,
@@ -39,12 +49,26 @@ public:
util::PaymentMode paymentMethod,
util::PaymentStatus status
);
Invoice(
const std::string& id,
const std::string& bookingId,
const util::Timestamp& invoiceDate,
const util::Vector<std::string>& partIDs,
double laborCost,
double partsCost,
double discountPercentage,
double totalAmount,
const util::Timestamp& paymentDate,
util::PaymentMode paymentMethod,
util::PaymentStatus status
);
const std::string& getId() const;
const std::string& getBookingId() const;
ServiceBooking* getBooking() const;
const util::Timestamp& getInvoiceDate() const;
double getLaborCost() const;
const util::Map<int, InventoryItem*>& getParts() const;
const util::Vector<std::string>& getPartIDs() const;
const util::Map<std::string, InventoryItem*>& getParts() const;
double getPartsCost() const;
double getDiscountPercentage() const;
double getTotalAmount() const;
@@ -56,11 +80,14 @@ public:
void setBooking(ServiceBooking* booking);
void setInvoiceDate(const util::Timestamp& invoiceDate);
void setLaborCost(double laborCost);
void setParts(const util::Map<int, InventoryItem*>& parts);
void setParts(const util::Map<std::string, InventoryItem*>& parts);
void setPartsCost(double partsCost);
void setDiscountPercentage(double discountPercentage);
void setTotalAmount(double totalAmount);
void setPaymentDate(const util::Timestamp& paymentDate);
void setPaymentMethod(util::PaymentMode paymentMethod);
void setStatus(util::PaymentStatus status);
std::string serialize() const;
static Invoice* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,7 +1,28 @@
/*
File: JobCard.cpp
Description: Implementation file containing the method definitions of the
JobCard class, including constructors, getters, and setters
for job card attributes.
Author: Trenser
Date:19-May-2026
*/
#include <sstream>
#include <stdexcept>
#include "JobCard.h"
#include "Factory.h"
#include "StringHelper.h"
#include "Enums.h"
int JobCard::m_uid = 0;
/*
Function: JobCard
Description: Default constructor that initializes a new job card with
a unique ID and default values.
Parameter: None
Return type: Constructor
*/
JobCard::JobCard()
: m_id("JC" + std::to_string(++m_uid)),
m_booking(nullptr),
@@ -9,6 +30,22 @@ JobCard::JobCard()
m_technician(nullptr),
m_status(util::ServiceJobStatus()) {}
/*
Function: JobCard
Description: Parameterized constructor that initializes a new job card with a unique ID and specified details.
Parameters:
- bookingId: ID of the associated service booking.
- booking: Pointer to the ServiceBooking object.
- service: Pointer to the Service object.
- serviceId: ID of the associated service.
- technicianId: ID of the assigned technician.
- technician: Pointer to the User object representing the technician.
- assignedDate: Timestamp of when the job was assigned.
- status: Current status of the job (STARTED/COMPLETED).
- completionDate: Timestamp of when the job was completed.
Returns:
- A new JobCard object.
*/
JobCard::JobCard(const std::string& bookingId,
ServiceBooking* booking,
Service* service,
@@ -30,102 +67,363 @@ JobCard::JobCard(const std::string& bookingId,
m_status(status),
m_completionDate(completionDate) {}
/*
Function: JobCard (parameterized constructor with ID)
Description: Initializes a job card with an existing ID, booking ID, service ID,
technician ID, assignment date, completion date, and status.
Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique job card ID
- bookingId: const std::string&, ID of the booking
- serviceId: const std::string&, ID of the service
- technicianId: const std::string&, ID of the technician
- assignedDate: const util::Timestamp&, date of assignment
- status: util::ServiceJobStatus, job status
- completionDate: const util::Timestamp&, date of completion
Returns:
- A new JobCard object
*/
JobCard::JobCard(const std::string& id,
const std::string& bookingId,
const std::string& serviceId,
const std::string& technicianId,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
const util::Timestamp& completionDate
)
: m_id(id),
m_bookingId(bookingId),
m_booking(nullptr),
m_service(nullptr),
m_serviceId(serviceId),
m_technicianId(technicianId),
m_technician(nullptr),
m_assignedDate(assignedDate),
m_status(status),
m_completionDate(completionDate)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the job card.
Returns:
- const std::string& representing the job card ID.
*/
const std::string& JobCard::getId() const
{
return m_id;
}
/*
Function: getBookingId
Description: Retrieves the booking ID associated with the job card.
Returns:
- const std::string& representing the booking ID.
*/
const std::string& JobCard::getBookingId() const
{
return m_bookingId;
}
/*
Function: getBooking
Description: Retrieves the pointer to the associated ServiceBooking.
Returns:
- ServiceBooking* representing the booking.
*/
ServiceBooking* JobCard::getBooking() const
{
return m_booking;
}
/*
Function: getService
Description: Retrieves the pointer to the associated Service.
Returns:
- Service* representing the service.
*/
Service* JobCard::getService() const
{
return m_service;
}
/*
Function: getServiceId
Description: Retrieves the service ID associated with the job card.
Returns:
- const std::string& representing the service ID.
*/
const std::string& JobCard::getServiceId() const
{
return m_serviceId;
}
/*
Function: getTechnicianId
Description: Retrieves the technician ID associated with the job card.
Returns:
- const std::string& representing the technician ID.
*/
const std::string& JobCard::getTechnicianId() const
{
return m_technicianId;
}
/*
Function: getTechnician
Description: Retrieves the pointer to the assigned technician.
Returns:
- User* representing the technician.
*/
User* JobCard::getTechnician() const
{
return m_technician;
}
/*
Function: getAssignedDate
Description: Retrieves the timestamp of when the job was assigned.
Returns:
- const util::Timestamp& representing the assigned date.
*/
const util::Timestamp& JobCard::getAssignedDate() const
{
return m_assignedDate;
}
/*
Function: getStatus
Description: Retrieves the current status of the job.
Returns:
- ServiceJobStatus representing the job status.
*/
util::ServiceJobStatus JobCard::getStatus() const
{
return m_status;
}
/*
Function: getCompletionDate
Description: Retrieves the timestamp of when the job was completed.
Returns:
- const util::Timestamp& representing the completion date.
*/
const util::Timestamp& JobCard::getCompletionDate() const
{
return m_completionDate;
}
/*
Function: setId
Description: Sets the unique ID of the job card.
Parameters:
- id: New job card ID string.
Returns:
- void
*/
void JobCard::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setBookingId
Description: Sets the booking ID associated with the job card.
Parameters:
- bookingId: New booking ID string.
Returns:
- void
*/
void JobCard::setBookingId(const std::string& bookingId)
{
m_bookingId = bookingId;
}
/*
Function: setBooking
Description: Sets the associated ServiceBooking pointer.
Parameters:
- booking: Pointer to the ServiceBooking object.
Returns:
- void
*/
void JobCard::setBooking(ServiceBooking* booking)
{
m_booking = booking;
}
/*
Function: setService
Description: Sets the associated Service pointer.
Parameters:
- service: Pointer to the Service object.
Returns:
- void
*/
void JobCard::setService(Service* service)
{
m_service = service;
}
/*
Function: setServiceId
Description: Sets the service ID associated with the job card.
Parameters:
- serviceId: New service ID string.
Returns:
- void
*/
void JobCard::setServiceId(const std::string& serviceId)
{
m_serviceId = serviceId;
}
/*
Function: setTechnicianId
Description: Sets the technician ID associated with the job card.
Parameters:
- technicianId: New technician ID string.
Returns:
- void
*/
void JobCard::setTechnicianId(const std::string& technicianId)
{
m_technicianId = technicianId;
}
/*
Function: setTechnician
Description: Sets the pointer to the assigned technician.
Parameters:
- technician: Pointer to the User object.
Returns:
- void
*/
void JobCard::setTechnician(User* technician)
{
m_technician = technician;
}
/*
Function: setAssignedDate
Description: Sets the timestamp of when the job was assigned.
Parameters:
- assignedDate: New timestamp for the assigned date.
Returns:
- void
*/
void JobCard::setAssignedDate(const util::Timestamp& assignedDate)
{
m_assignedDate = assignedDate;
}
/*
Function: setStatus
Description: Sets the current status of the job.
Parameters:
- status: New job status value.
Returns:
- void
*/
void JobCard::setStatus(util::ServiceJobStatus status)
{
m_status = status;
}
/*
Function: setCompletionDate
Description: Sets the timestamp of when the job was completed.
Parameters:
- completionDate: New timestamp for the completion date.
Returns:
- void
*/
void JobCard::setCompletionDate(const util::Timestamp& completionDate)
{
m_completionDate = completionDate;
}
/*
Function: serialize
Description: Serializes the job card into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized job card record
*/
std::string JobCard::serialize() const
{
std::ostringstream serializedJobCard;
serializedJobCard << m_id << ','
<< m_bookingId << ','
<< m_serviceId << ','
<< m_technicianId << ','
<< m_assignedDate.toString() << ','
<< util::getServiceJobStatusString(m_status) << ','
<< m_completionDate.toString();
return serializedJobCard.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a JobCard object.
Parameters:
- record: const std::string&, serialized job card record
Returns:
- JobCard*: Pointer to the deserialized JobCard object
Throws:
- std::runtime_error if timestamp parsing fails
*/
JobCard* JobCard::deserialize(const std::string& record)
{
std::string id, bookingId, serviceId, technicianId;
std::string assignedDateString, statusString, completionDateString;
std::istringstream serializedJobCard(record);
getline(serializedJobCard, id, ',');
getline(serializedJobCard, bookingId, ',');
getline(serializedJobCard, serviceId, ',');
getline(serializedJobCard, technicianId, ',');
getline(serializedJobCard, assignedDateString, ',');
getline(serializedJobCard, statusString, ',');
getline(serializedJobCard, completionDateString, ',');
util::Timestamp assignedDate;
util::Timestamp completionDate;
try
{
assignedDate = util::Timestamp::fromString(assignedDateString);
completionDate = util::Timestamp::fromString(completionDateString);
}
catch (...)
{
throw std::runtime_error("Invalid timestamp");
}
util::ServiceJobStatus status = util::getServiceJobStatus(statusString);
return Factory::getObject<JobCard>(
id,
bookingId,
serviceId,
technicianId,
assignedDate,
status,
completionDate
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for job card serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate")
*/
std::string JobCard::getHeaders()
{
return "ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate";
}
@@ -1,7 +1,16 @@
/*
File: JobCard.h
Description: Header file declaring the JobCard class, which represents
a service job card containing booking, service, technician,
and status details.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "Timestamp.h"
#include "Enums.h"
#include "Timestamp.h"
class ServiceBooking;
class Service;
@@ -21,7 +30,6 @@ private:
util::Timestamp m_assignedDate;
util::ServiceJobStatus m_status;
util::Timestamp m_completionDate;
public:
JobCard();
JobCard(const std::string& bookingId,
@@ -34,6 +42,14 @@ public:
util::ServiceJobStatus status,
const util::Timestamp& completionDate
);
JobCard(const std::string& id,
const std::string& bookingId,
const std::string& serviceId,
const std::string& technicianId,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
const util::Timestamp& completionDate
);
const std::string& getId() const;
const std::string& getBookingId() const;
ServiceBooking* getBooking() const;
@@ -54,4 +70,7 @@ public:
void setAssignedDate(const util::Timestamp& assignedDate);
void setStatus(util::ServiceJobStatus status);
void setCompletionDate(const util::Timestamp& completionDate);
std::string serialize() const;
static JobCard* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,11 +1,42 @@
/*
File: Notification.cpp
Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for notification details such as ID, recipient, title, message, and timestamp.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include "Notification.h"
#include "StringHelper.h"
#include "Factory.h"
int Notification::m_uid = 0;
/*
Function: Notification
Description: Default constructor that initializes a new notification with a unique ID and null recipient.
Parameters:
- None
Returns:
- A new Notification object.
*/
Notification::Notification()
: m_id("NOT" + std::to_string(++m_uid)),
m_recipient(nullptr) {}
/*
Function: Notification
Description: Parameterized constructor that initializes a new notification with a unique ID and specified details.
Parameters:
- recipientUserId: ID of the recipient user.
- recipient: Pointer to the User object representing the recipient.
- title: Title of the notification.
- message: Message content of the notification.
- createdAt: Timestamp of when the notification was created.
Returns:
- A new Notification object.
*/
Notification::Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt)
: m_id("NOT" + std::to_string(++m_uid)),
m_recipientUserId(recipientUserId),
@@ -14,62 +45,243 @@ Notification::Notification(const std::string& recipientUserId, User* recipient,
m_message(message),
m_createdAt(createdAt) {}
/*
Function: Notification (parameterized constructor with ID)
Description: Initializes a notification with an existing ID, recipient details,
title, message, and creation timestamp. Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique notification ID
- recipientUserId: const std::string&, ID of the recipient user
- title: const std::string&, notification title
- message: const std::string&, notification message
- createdAt: const util::Timestamp&, timestamp of creation
Returns:
- A new Notification object
*/
Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt)
: m_id(id),
m_recipientUserId(recipientUserId),
m_recipient(nullptr),
m_title(title),
m_message(message),
m_createdAt(createdAt)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the notification.
Returns:
- const std::string& representing the notification ID.
*/
const std::string& Notification::getId() const
{
return m_id;
}
/*
Function: getRecipientUserId
Description: Retrieves the recipient user ID associated with the notification.
Returns:
- const std::string& representing the recipient user ID.
*/
const std::string& Notification::getRecipientUserId() const
{
return m_recipientUserId;
}
/*
Function: getRecipient
Description: Retrieves the pointer to the recipient user.
Returns:
- User* representing the recipient.
*/
User* Notification::getRecipient() const
{
return m_recipient;
}
/*
Function: getTitle
Description: Retrieves the title of the notification.
Returns:
- const std::string& representing the notification title.
*/
const std::string& Notification::getTitle() const
{
return m_title;
}
/*
Function: getMessage
Description: Retrieves the message content of the notification.
Returns:
- const std::string& representing the notification message.
*/
const std::string& Notification::getMessage() const
{
return m_message;
}
/*
Function: getCreatedAt
Description: Retrieves the timestamp of when the notification was created.
Returns:
- const util::Timestamp& representing the creation timestamp.
*/
const util::Timestamp& Notification::getCreatedAt() const
{
return m_createdAt;
}
/*
Function: setId
Description: Sets the unique ID of the notification.
Parameters:
- id: New notification ID string.
Returns:
- void
*/
void Notification::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setRecipientUserId
Description: Sets the recipient user ID for the notification.
Parameters:
- recipientUserId: New recipient user ID string.
Returns:
- void
*/
void Notification::setRecipientUserId(const std::string& recipientUserId)
{
m_recipientUserId = recipientUserId;
}
/*
Function: setRecipient
Description: Sets the recipient user pointer for the notification.
Parameters:
- recipient: Pointer to the User object.
Returns:
- void
*/
void Notification::setRecipient(User* recipient)
{
m_recipient = recipient;
}
/*
Function: setTitle
Description: Sets the title of the notification.
Parameters:
- title: New notification title string.
Returns:
- void
*/
void Notification::setTitle(const std::string& title)
{
m_title = title;
}
/*
Function: setMessage
Description: Sets the message content of the notification.
Parameters:
- message: New notification message string.
Returns:
- void
*/
void Notification::setMessage(const std::string& message)
{
m_message = message;
}
/*
Function: setCreatedAt
Description: Sets the timestamp of when the notification was created.
Parameters:
- createdAt: New timestamp value.
Returns:
- void
*/
void Notification::setCreatedAt(const util::Timestamp& createdAt)
{
m_createdAt = createdAt;
}
/*
Function: serialize
Description: Serializes the notification into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized notification record
*/
std::string Notification::serialize() const
{
std::ostringstream serializedNotification;
serializedNotification << m_id << ','
<< m_recipientUserId << ','
<< m_title << ','
<< m_message << ','
<< m_createdAt.toString();
return serializedNotification.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a Notification object.
Parameters:
- record: const std::string&, serialized notification record
Returns:
- Notification*: Pointer to the deserialized Notification object
Throws:
- std::runtime_error if timestamp parsing fails
*/
Notification* Notification::deserialize(const std::string& record)
{
std::string id, recipientUserId, title, message, createdAtTimestampString;
std::istringstream serializedNotification(record);
getline(serializedNotification, id, ',');
getline(serializedNotification, recipientUserId, ',');
getline(serializedNotification, title, ',');
getline(serializedNotification, message, ',');
getline(serializedNotification, createdAtTimestampString, ',');
util::Timestamp createdAtTimestamp;
try
{
createdAtTimestamp = util::Timestamp::fromString(createdAtTimestampString);
}
catch (...)
{
throw std::runtime_error("Invalid createdAt timestamp");
}
return Factory::getObject<Notification>(
id,
recipientUserId,
title,
message,
createdAtTimestamp
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for notification serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,RecipientID,Title,Message,Timestamp")
*/
std::string Notification::getHeaders()
{
return "ID,RecipientID,Title,Message,Timestamp";
}
@@ -1,3 +1,11 @@
/*
File: Notification.h
Description: Declares the Notification class which represents system messages sent to users in the Vehicle Service Management System.
Each notification includes a unique ID, recipient details, title, message content, and timestamp of creation.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Timestamp.h"
@@ -17,6 +25,7 @@ private:
public:
Notification();
Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
const std::string& getId() const;
const std::string& getRecipientUserId() const;
User* getRecipient() const;
@@ -29,4 +38,7 @@ public:
void setTitle(const std::string& title);
void setMessage(const std::string& message);
void setCreatedAt(const util::Timestamp& createdAt);
std::string serialize() const;
static Notification* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,65 +1,337 @@
/*
File: Service.cpp
Description: Implements the Service class which represents a vehicle service in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for service details such as ID, name, required inventory items,
labor cost, and state.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include "Service.h"
#include "InventoryItem.h"
#include "StringHelper.h"
#include "Factory.h"
int Service::m_uid = 0;
/*
Function: Service
Description: Default constructor that initializes a new service with a unique ID,
active state, and zero labor cost.
Parameters:
- None
Returns:
- A new Service object.
*/
Service::Service()
: m_id("SRV" + std::to_string(++m_uid)),
m_status(util::State::ACTIVE),
m_laborCost(0.0) {}
/*
Function: Service
Description: Parameterized constructor that initializes a new service with a unique ID and specified details.
Parameters:
- name: Name of the service.
- requiredInventoryItems: Map of inventory items required for the service.
- laborCost: Labor cost associated with the service.
Returns:
- A new Service object.
*/
Service::Service(const std::string& name, const util::Map<std::string, InventoryItem*>& requiredInventoryItems, double laborCost)
: m_id("SRV" + std::to_string(++m_uid)),
m_name(name),
m_requiredInventoryItems(requiredInventoryItems),
m_status(util::State::ACTIVE),
m_laborCost(laborCost) {}
m_laborCost(laborCost)
{
int numberOfInventoryItems = m_requiredInventoryItems.getSize();
auto inventoryItemPointers = m_requiredInventoryItems.getValues();
for (int index = 0; index < numberOfInventoryItems; index++)
{
m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId());
}
}
/*
Function: Service (parameterized constructor with ID)
Description: Initializes a service with an existing ID, name, inventory item IDs,
labor cost, and state. Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique service ID
- name: const std::string&, name of the service
- requiredInventoryItemIDs: const util::Vector<std::string>&, IDs of required inventory items
- laborCost: double, labor cost of the service
- status: util::State, state of the service (ACTIVE/INACTIVE)
Returns:
- A new Service object
*/
Service::Service(const std::string& id, const std::string& name, const util::Vector<std::string>& requiredInventoryItemIDs, double laborCost, util::State status)
: m_id(id),
m_name(name),
m_requiredInventoryItemIDs(requiredInventoryItemIDs),
m_status(status),
m_laborCost(laborCost)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the service.
Returns:
- const std::string& representing the service ID.
*/
const std::string& Service::getId() const
{
return m_id;
}
/*
Function: getName
Description: Retrieves the name of the service.
Returns:
- const std::string& representing the service name.
*/
const std::string& Service::getName() const
{
return m_name;
}
/*
Function: getRequiredInventoryItemIDs
Description: Retrieves the IDs of required inventory items for the service.
Parameters:
- None
Returns:
- const util::Vector<std::string>&: Inventory item IDs
*/
const util::Vector<std::string>& Service::getRequiredInventoryItemIDs() const
{
return m_requiredInventoryItemIDs;
}
/*
Function: getRequiredInventoryItems
Description: Retrieves the map of inventory items required for the service.
Returns:
- const util::Map<std::string, InventoryItem*>& representing the required inventory items.
*/
const util::Map<std::string, InventoryItem*>& Service::getRequiredInventoryItems() const
{
return m_requiredInventoryItems;
}
/*
Function: getLaborCost
Description: Retrieves the labor cost associated with the service.
Returns:
- double representing the labor cost.
*/
double Service::getLaborCost() const
{
return m_laborCost;
}
/*
Function: getState
Description: Retrieves the current state (ACTIVE/INACTIVE) of the service.
Returns:
- util::State representing the service state.
*/
util::State Service::getState() const
{
return m_status;
}
/*
Function: setId
Description: Sets the unique ID of the service.
Parameters:
- id: New service ID string.
Returns:
- void
*/
void Service::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setName
Description: Sets the name of the service.
Parameters:
- name: New service name string.
Returns:
- void
*/
void Service::setName(const std::string& name)
{
m_name = name;
}
/*
Function: setRequiredInventoryItems
Description: Sets the inventory items required for the service.
Parameters:
- requiredInventoryItems: Map of inventory items.
Returns:
- void
*/
void Service::setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems)
{
m_requiredInventoryItems = requiredInventoryItems;
m_requiredInventoryItemIDs.clear();
int numberOfRequiredInventoryItems = m_requiredInventoryItems.getSize();
auto inventoryItemPointers = m_requiredInventoryItems.getValues();
for (int index = 0; index < numberOfRequiredInventoryItems; index++)
{
m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId());
}
}
/*
Function: setLaborCost
Description: Sets the labor cost for the service.
Parameters:
- laborCost: New labor cost value.
Returns:
- void
*/
void Service::setLaborCost(double laborCost)
{
m_laborCost = laborCost;
}
/*
Function: setState
Description: Sets the state (ACTIVE/INACTIVE) of the service.
Parameters:
- status: New state value.
Returns:
- void
*/
void Service::setState(util::State status)
{
m_status = status;
}
/*
Function: getInventoryItemIDsAsString (static helper)
Description: Converts a vector of inventory item IDs into a single string separated by '|'.
Parameters:
- inventoryItemIds: const util::Vector<std::string>&, vector of inventory item IDs
Returns:
- std::string: Concatenated inventory item IDs string
*/
static std::string getInventoryItemIDsAsString(const util::Vector<std::string>& inventoryItemIds)
{
int numberOfInventoryItems = inventoryItemIds.getSize();
std::string inventoryItemIDs;
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItemIDs += inventoryItemIds[index];
if (index < numberOfInventoryItems - 1)
{
inventoryItemIDs += '|';
}
}
return inventoryItemIDs;
}
/*
Function: getInventoryItemIDsAsVector (static helper)
Description: Converts a string of inventory item IDs separated by '|' into a vector.
Parameters:
- inventoryItemIDsString: const std::string&, concatenated inventory item IDs string
Returns:
- util::Vector<std::string>: Vector of inventory item IDs
*/
static util::Vector<std::string> getInventoryItemIDsAsVector(const std::string& inventoryItemIDsString)
{
util::Vector<std::string> inventoryItemIDs;
std::string inventoryItemID;
std::istringstream serializedInventoryItemIDs(inventoryItemIDsString);
while (getline(serializedInventoryItemIDs, inventoryItemID, '|'))
{
inventoryItemIDs.push_back(inventoryItemID);
}
return inventoryItemIDs;
}
/*
Function: serialize
Description: Serializes the service into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized service record
*/
std::string Service::serialize() const
{
std::ostringstream serializedService;
serializedService << m_id << ','
<< m_name << ','
<< getInventoryItemIDsAsString(m_requiredInventoryItemIDs) << ','
<< m_laborCost << ','
<< util::getStateString(m_status);
return serializedService.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a Service object.
Parameters:
- record: const std::string&, serialized service record
Returns:
- Service*: Pointer to the deserialized Service object
Throws:
- std::runtime_error if labor cost parsing fails
*/
Service* Service::deserialize(const std::string& record)
{
std::string id, name;
std::string inventoryItemIDsString, laborCostString, statusString;
double laborCost;
std::istringstream serializedService(record);
getline(serializedService, id, ',');
getline(serializedService, name, ',');
getline(serializedService, inventoryItemIDsString, ',');
getline(serializedService, laborCostString, ',');
getline(serializedService, statusString, ',');
util::Vector<std::string> inventoryItemIDs = getInventoryItemIDsAsVector(inventoryItemIDsString);
try
{
laborCost = std::stod(laborCostString);
}
catch (...)
{
throw std::runtime_error("Invalid labor cost");
}
util::State status = util::getState(statusString);
return Factory::getObject<Service>(
id,
name,
inventoryItemIDs,
laborCost,
status
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for service serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Name,InventoryIDs,LaborCost,Status")
*/
std::string Service::getHeaders()
{
return "ID,Name,InventoryIDs,LaborCost,Status";
}
@@ -1,6 +1,16 @@
/*
File: Service.h
Description: Declares the Service class which represents a vehicle service in the Vehicle Service Management System.
Each service includes a unique ID, name, required inventory items, labor cost, and status.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
#include "Enums.h"
class InventoryItem;
@@ -11,14 +21,17 @@ private:
static int m_uid;
std::string m_id;
std::string m_name;
util::Vector<std::string> m_requiredInventoryItemIDs;
util::Map<std::string, InventoryItem*> m_requiredInventoryItems;
double m_laborCost;
util::State m_status;
public:
Service();
Service(const std::string& name, const util::Map<std::string, InventoryItem*>& requiredInventoryItems, double laborCost);
Service(const std::string& id, const std::string& name, const util::Vector<std::string>& requiredInventoryItemIDs, double laborCost, util::State state);
const std::string& getId() const;
const std::string& getName() const;
const util::Vector<std::string>& getRequiredInventoryItemIDs() const;
const util::Map<std::string, InventoryItem*>& getRequiredInventoryItems() const;
double getLaborCost() const;
util::State getState() const;
@@ -27,4 +40,7 @@ public:
void setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems);
void setLaborCost(double laborCost);
void setState(util::State status);
std::string serialize() const;
static Service* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,14 +1,52 @@
/*
File: ServiceBooking.cpp
Description: Implementation file containing the method definitions of the
ServiceBooking class, including constructors, getters, and setters
for booking attributes.
Author: Trenser
Date:19-May-2026
*/
#include <stdexcept>
#include <sstream>
#include "ServiceBooking.h"
#include "Service.h"
#include "Enums.h"
#include "Factory.h"
#include "StringHelper.h"
int ServiceBooking::m_uid = 0;
/*
Function: ServiceBooking
Description: Default constructor that initializes a new service booking with a unique ID,
null customer, and zero discount percentage.
Parameters: None
Returns: A new ServiceBooking object.
*/
ServiceBooking::ServiceBooking()
: m_id("SRV" + std::to_string(++m_uid)),
: m_id("SBK" + std::to_string(++m_uid)),
m_customer(nullptr),
m_assignedTechnician(nullptr),
m_status(util::ServiceJobStatus::PENDING),
m_discountPercentage(0.0) {}
/*
Function: ServiceBooking
Description: Parameterized constructor that initializes a new service booking with a unique ID and specified details.
Parameters:
- id: Booking ID string.
- status: Current status of the booking (e.g., PENDING, COMPLETED).
- services: Map of services included in the booking.
- customerId: ID of the customer.
- customer: Pointer to the User object representing the customer.
- vehicleNumber: Vehicle registration number.
- vehicleBrand: Brand of the vehicle.
- vehicleModel: Model of the vehicle.
- discountPercentage: Discount applied to the booking.
Returns:
- A new ServiceBooking object.
*/
ServiceBooking::ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Map<std::string,
Service*>& services,
@@ -17,11 +55,9 @@ ServiceBooking::ServiceBooking(
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
const User* assignedTechnician,
double discountPercentage
)
: m_id("SRV" + std::to_string(++m_uid)),
: m_id("SBK" + std::to_string(++m_uid)),
m_status(status),
m_services(services),
m_customerId(customerId),
@@ -29,118 +65,456 @@ ServiceBooking::ServiceBooking(
m_vehicleNumber(vehicleNumber),
m_vehicleBrand(vehicleBrand),
m_vehicleModel(vehicleModel),
m_assignedTechnicianId(assignedTechnicianId),
m_assignedTechnician(assignedTechnician),
m_assignedTechnicianId(""),
m_assignedTechnician(nullptr),
m_discountPercentage(discountPercentage)
{
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
/*
Function: ServiceBooking (parameterized constructor with ID)
Description: Initializes a service booking with an existing ID, status, service IDs,
customer details, vehicle details, technician ID, and discount percentage.
Updates UID tracking based on ID.
Parameters:
- id: const std::string&, unique booking ID
- status: util::ServiceJobStatus, job status of the booking
- serviceIDs: const util::Vector<std::string>&, IDs of booked services
- customerId: const std::string&, ID of the customer
- vehicleNumber: const std::string&, vehicle number
- vehicleBrand: const std::string&, vehicle brand
- vehicleModel: const std::string&, vehicle model
- assignedTechnicianId: const std::string&, ID of the assigned technician
- discountPercentage: double, discount applied
Returns:
- A new ServiceBooking object
*/
ServiceBooking::ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Vector<std::string>& serviceIDs,
const std::string& customerId,
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
double discountPercentage
)
: m_id(id),
m_status(status),
m_serviceIDs(serviceIDs),
m_customerId(customerId),
m_customer(nullptr),
m_vehicleNumber(vehicleNumber),
m_vehicleBrand(vehicleBrand),
m_vehicleModel(vehicleModel),
m_assignedTechnicianId(assignedTechnicianId),
m_assignedTechnician(nullptr),
m_discountPercentage(discountPercentage)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique identifier of the service booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getId() const
{
return m_id;
}
/*
Function: getStatus
Description: Retrieves the current status of the service booking.
Parameter: None
Return type: util::ServiceJobStatus
*/
util::ServiceJobStatus ServiceBooking::getStatus() const
{
return m_status;
}
/*
Function: getServiceIDs
Description: Retrieves the IDs of services booked.
Parameters:
- None
Returns:
- const util::Vector<std::string>&: Service IDs
*/
const util::Vector<std::string>& ServiceBooking::getServiceIDs() const
{
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
Description: Retrieves the services associated with the booking.
Parameter: None
Return type: const util::Map<std::string, Service*>&
*/
const util::Map<std::string, Service*>& ServiceBooking::getServices() const
{
return m_services;
}
/*
Function: getCustomerId
Description: Retrieves the customer ID associated with the booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getCustomerId() const
{
return m_customerId;
}
/*
Function: getCustomer
Description: Retrieves the customer object associated with the booking.
Parameter: None
Return type: User*
*/
User* ServiceBooking::getCustomer() const
{
return m_customer;
}
/*
Function: getVehicleNumber
Description: Retrieves the vehicle registration number for the booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getVehicleNumber() const
{
return m_vehicleNumber;
}
/*
Function: getVehicleBrand
Description: Retrieves the brand of the vehicle for the booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getVehicleBrand() const
{
return m_vehicleBrand;
}
/*
Function: getVehicleModel
Description: Retrieves the model of the vehicle for the booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getVehicleModel() const
{
return m_vehicleModel;
}
/*
Function: getAssignedTechnicianId
Description: Retrieves the ID of the technician assigned to the booking.
Parameter: None
Return type: const std::string&
*/
const std::string& ServiceBooking::getAssignedTechnicianId() const
{
return m_assignedTechnicianId;
}
const User* ServiceBooking::getAssignedTechnician() const
/*
Function: getAssignedTechnician
Description: Retrieves the technician object assigned to the booking.
Parameter: None
Return type: User*
*/
User* ServiceBooking::getAssignedTechnician() const
{
return m_assignedTechnician;
}
/*
Function: getDiscountPercentage
Description: Retrieves the discount percentage applied to the booking.
Parameter: None
Return type: double
*/
double ServiceBooking::getDiscountPercentage() const
{
return m_discountPercentage;
}
/*
Function: setId
Description: Sets the unique identifier of the service booking.
Parameter: const std::string& id - new booking ID
Return type: void
*/
void ServiceBooking::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setStatus
Description: Sets the current status of the service booking.
Parameter: const util::ServiceJobStatus& status - new booking status
Return type: void
*/
void ServiceBooking::setStatus(const util::ServiceJobStatus& status)
{
m_status = status;
}
/*
Function: setServices
Description: Sets the services associated with the booking.
Parameter: const util::Map<std::string, Service*>& services - new services map
Return type: void
*/
void ServiceBooking::setServices(const util::Map<std::string, Service*>& services)
{
m_services = services;
m_serviceIDs.clear();
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
/*
Function: setCustomerId
Description: Sets the customer ID for the booking.
Parameter: const std::string& customerId - new customer ID
Return type: void
*/
void ServiceBooking::setCustomerId(const std::string& customerId)
{
m_customerId = customerId;
}
/*
Function: setCustomer
Description: Sets the customer object for the booking.
Parameter: User* customer - pointer to the customer object
Return type: void
*/
void ServiceBooking::setCustomer(User* customer)
{
m_customer = customer;
}
/*
Function: setVehicleNumber
Description: Sets the vehicle registration number for the booking.
Parameter: const std::string& vehicleNumber - new vehicle number
Return type: void
*/
void ServiceBooking::setVehicleNumber(const std::string& vehicleNumber)
{
m_vehicleNumber = vehicleNumber;
}
/*
Function: setVehicleBrand
Description: Sets the brand of the vehicle for the booking.
Parameter: const std::string& vehicleBrand - new vehicle brand
Return type: void
*/
void ServiceBooking::setVehicleBrand(const std::string& vehicleBrand)
{
m_vehicleBrand = vehicleBrand;
}
/*
Function: setVehicleModel
Description: Sets the model of the vehicle for the booking.
Parameter: const std::string& vehicleModel - new vehicle model
Return type: void
*/
void ServiceBooking::setVehicleModel(const std::string& vehicleModel)
{
m_vehicleModel = vehicleModel;
}
/*
Function: setAssignedTechnicianId
Description: Sets the ID of the technician assigned to the booking.
Parameter: const std::string& assignedTechnicianId - new technician ID
Return type: void
*/
void ServiceBooking::setAssignedTechnicianId(const std::string& assignedTechnicianId)
{
m_assignedTechnicianId = assignedTechnicianId;
}
void ServiceBooking::setAssignedTechnician(const User* assignedTechnician)
/*
Function: setAssignedTechnician
Description: Sets the technician object assigned to the booking.
Parameter: User* assignedTechnician - pointer to the technician object
Return type: void
*/
void ServiceBooking::setAssignedTechnician(User* assignedTechnician)
{
m_assignedTechnician = assignedTechnician;
}
/*
Function: setDiscountPercentage
Description: Sets the discount percentage for the booking.
Parameter: double discountPercentage - new discount percentage
Return type: void
*/
void ServiceBooking::setDiscountPercentage(double discountPercentage)
{
m_discountPercentage = discountPercentage;
}
/*
Function: getServiceIDsAsString (static helper)
Description: Converts a vector of service IDs into a single string separated by '|'.
Parameters:
- serviceIDs: const util::Vector<std::string>&, vector of service IDs
Returns:
- std::string: Concatenated service IDs string
*/
static std::string getServiceIDsAsString(const util::Vector<std::string>& serviceIDs)
{
int numberOfServices = serviceIDs.getSize();
std::string serviceIDsString;
for (int index = 0; index < numberOfServices; index++)
{
serviceIDsString += serviceIDs[index];
if (index < numberOfServices - 1)
{
serviceIDsString += '|';
}
}
return serviceIDsString;
}
/*
Function: getServiceIDsAsVector (static helper)
Description: Converts a string of service IDs separated by '|' into a vector.
Parameters:
- serviceIDsString: const std::string&, concatenated service IDs string
Returns:
- util::Vector<std::string>: Vector of service IDs
*/
static util::Vector<std::string> getServiceIDsAsVector(const std::string& serviceIDsString)
{
util::Vector<std::string> serviceIDs;
std::string serviceID;
std::istringstream serializedServiceIDs(serviceIDsString);
while (getline(serializedServiceIDs, serviceID, '|'))
{
serviceIDs.push_back(serviceID);
}
return serviceIDs;
}
/*
Function: serialize
Description: Serializes the service booking into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized booking record
*/
std::string ServiceBooking::serialize() const
{
std::ostringstream serializedBooking;
serializedBooking << m_id << ','
<< util::getServiceJobStatusString(m_status) << ','
<< getServiceIDsAsString(m_serviceIDs) << ','
<< m_customerId << ','
<< m_vehicleNumber << ','
<< m_vehicleBrand << ','
<< m_vehicleModel << ','
<< m_assignedTechnicianId << ','
<< m_discountPercentage << ',';
return serializedBooking.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a ServiceBooking object.
Parameters:
- record: const std::string&, serialized booking record
Returns:
- ServiceBooking*: Pointer to the deserialized ServiceBooking object
Throws:
- std::runtime_error if discount percentage parsing fails
*/
ServiceBooking* ServiceBooking::deserialize(const std::string& record)
{
std::string id, customerId, vehicleNumber, vehicleBrand, vehicleModel, assignedTechnicianId;
std::string serviceJobStatusString, serviceIDsString, discountPercentageString;
double discountPercentage;
std::istringstream serializedBooking(record);
getline(serializedBooking, id, ',');
getline(serializedBooking, serviceJobStatusString, ',');
getline(serializedBooking, serviceIDsString, ',');
getline(serializedBooking, customerId, ',');
getline(serializedBooking, vehicleNumber, ',');
getline(serializedBooking, vehicleBrand, ',');
getline(serializedBooking, vehicleModel, ',');
getline(serializedBooking, assignedTechnicianId, ',');
getline(serializedBooking, discountPercentageString, ',');
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid discount percentage");
}
util::ServiceJobStatus status = util::getServiceJobStatus(serviceJobStatusString);
return Factory::getObject<ServiceBooking>(
id,
status,
serviceIDs,
customerId,
vehicleNumber,
vehicleBrand,
vehicleModel,
assignedTechnicianId,
discountPercentage
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for service booking serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage")
*/
std::string ServiceBooking::getHeaders()
{
return "ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage";
}
@@ -1,6 +1,15 @@
/*
File: ServiceBooking.h
Description: Header file declaring the ServiceBooking class, which represents
a booking of services by a customer, including vehicle details,
assigned technician, and discount information.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
#include "Enums.h"
class Service;
@@ -12,6 +21,7 @@ private:
static int m_uid;
std::string m_id;
util::ServiceJobStatus m_status;
util::Vector<std::string> m_serviceIDs;
util::Map<std::string, Service*> m_services;
std::string m_customerId;
User* m_customer;
@@ -19,12 +29,11 @@ private:
std::string m_vehicleBrand;
std::string m_vehicleModel;
std::string m_assignedTechnicianId;
const User* m_assignedTechnician;
User* m_assignedTechnician;
double m_discountPercentage;
public:
ServiceBooking();
ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Map<std::string,
Service*>& services,
@@ -33,12 +42,22 @@ public:
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
double discountPercentage
);
ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Vector<std::string>& serviceIDs,
const std::string& customerId,
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
const User* assignedTechnician,
double discountPercentage
);
const std::string& getId() const;
util::ServiceJobStatus getStatus() const;
const util::Vector<std::string>& getServiceIDs() const;
const util::Map<std::string, Service*>& getServices() const;
const std::string& getCustomerId() const;
User* getCustomer() const;
@@ -46,7 +65,7 @@ public:
const std::string& getVehicleBrand() const;
const std::string& getVehicleModel() const;
const std::string& getAssignedTechnicianId() const;
const User* getAssignedTechnician() const;
User* getAssignedTechnician() const;
double getDiscountPercentage() const;
void setId(const std::string& id);
void setStatus(const util::ServiceJobStatus& status);
@@ -57,6 +76,9 @@ public:
void setVehicleBrand(const std::string& vehicleBrand);
void setVehicleModel(const std::string& vehicleModel);
void setAssignedTechnicianId(const std::string& assignedTechnicianId);
void setAssignedTechnician(const User* assignedTechnician);
void setAssignedTechnician(User* assignedTechnician);
void setDiscountPercentage(double discountPercentage);
std::string serialize() const;
static ServiceBooking* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,14 +1,48 @@
/*
File: User.cpp
Description: Implements the User class which represents system users in the Vehicle Service Management System.
Provides constructors, destructor, accessors, and mutators for user details such as ID, username,
password, name, phone, email, role, state, and notifications.
Author: Trenser
Date: 19-May-2026
*/
#include <sstream>
#include "User.h"
#include "Notification.h"
#include "Enums.h"
#include "Factory.h"
#include "StringHelper.h"
int User::m_uid = 0;
/*
Function: User
Description: Default constructor that initializes a new user with a unique ID,
default role as CUSTOMER, and active state.
Parameters:
- None
Returns:
- A new User object.
*/
User::User()
: m_id("USR" + std::to_string(++m_uid)),
m_type(util::UserType::CUSTOMER),
m_status(util::State::ACTIVE) {}
/*
Function: User
Description: Parameterized constructor that initializes a new user with a unique ID and specified details.
Parameters:
- userName: Username for login.
- password: Password for authentication.
- name: Full name of the user.
- phone: Phone number of the user.
- email: Email address of the user.
- role: Role of the user (CUSTOMER, ADMIN, TECHNICIAN, etc.).
Returns:
- A new User object.
*/
User::User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role)
: m_id("USR" + std::to_string(++m_uid)),
m_userName(userName),
@@ -19,104 +53,339 @@ User::User(const std::string& userName, const std::string& password, const std::
m_type(role),
m_status(util::State::ACTIVE) {}
User::~User()
/*
Function: User (parameterized constructor with ID)
Description: Initializes a user with an existing ID, credentials, personal details,
role, and state. Updates UID tracking based on ID.
Parameters:
- userId: const std::string&, unique user ID
- userName: const std::string&, username
- password: const std::string&, password
- name: const std::string&, full name
- phone: const std::string&, phone number
- email: const std::string&, email address
- role: util::UserType, role of the user
- status: util::State, state of the user (ACTIVE/INACTIVE)
Returns:
- A new User object
*/
User::User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status)
: m_id(userId),
m_userName(userName),
m_password(password),
m_name(name),
m_phone(phone),
m_email(email),
m_type(role),
m_status(status)
{
for (int index = 0; index < m_notifications.getSize(); index++)
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
delete m_notifications.getValues()[index];
m_uid = idNumber;
}
}
/*
Function: ~User
Description: Destructor that cleans up dynamically allocated notifications associated with the user.
Parameters:
- None
Returns:
- void
*/
User::~User()
{
auto values = m_notifications.getValues();
for (int index = 0; index < values.getSize(); index++)
{
delete values[index];
}
}
/*
Function: getId
Description: Retrieves the unique ID of the user.
Returns:
- const std::string& representing the user ID.
*/
const std::string& User::getId() const
{
return m_id;
}
/*
Function: getUserName
Description: Retrieves the username of the user.
Returns:
- const std::string& representing the username.
*/
const std::string& User::getUserName() const
{
return m_userName;
}
/*
Function: getPassword
Description: Retrieves the password of the user.
Returns:
- const std::string& representing the password.
*/
const std::string& User::getPassword() const
{
return m_password;
}
/*
Function: getName
Description: Retrieves the full name of the user.
Returns:
- const std::string& representing the name.
*/
const std::string& User::getName() const
{
return m_name;
}
/*
Function: getPhone
Description: Retrieves the phone number of the user.
Returns:
- const std::string& representing the phone number.
*/
const std::string& User::getPhone() const
{
return m_phone;
}
/*
Function: getEmail
Description: Retrieves the email address of the user.
Returns:
- const std::string& representing the email.
*/
const std::string& User::getEmail() const
{
return m_email;
}
/*
Function: getNotifications
Description: Retrieves the map of notifications associated with the user.
Returns:
- util::Map<std::string, Notification*>& representing the notifications.
*/
util::Map<std::string, Notification*>& User::getNotifications()
{
return m_notifications;
}
/*
Function: getUserType
Description: Retrieves the role of the user.
Returns:
- util::UserType representing the user role.
*/
util::UserType User::getUserType() const
{
return m_type;
}
/*
Function: getState
Description: Retrieves the current state (ACTIVE/INACTIVE) of the user.
Returns:
- util::State representing the user state.
*/
util::State User::getState() const
{
return m_status;
}
/*
Function: setId
Description: Sets the unique ID of the user.
Parameters:
- id: New user ID string.
Returns:
- void
*/
void User::setId(const std::string& id)
{
m_id = id;
}
/*
Function: setUserName
Description: Sets the username of the user.
Parameters:
- userName: New username string.
Returns:
- void
*/
void User::setUserName(const std::string& userName)
{
m_userName = userName;
}
/*
Function: setPassword
Description: Sets the password of the user.
Parameters:
- password: New password string.
Returns:
- void
*/
void User::setPassword(const std::string& password)
{
m_password = password;
}
/*
Function: setName
Description: Sets the full name of the user.
Parameters:
- name: New name string.
Returns:
- void
*/
void User::setName(const std::string& name)
{
m_name = name;
}
/*
Function: setPhone
Description: Sets the phone number of the user.
Parameters:
- phone: New phone number string.
Returns:
- void
*/
void User::setPhone(const std::string& phone)
{
m_phone = phone;
}
/*
Function: setEmail
Description: Sets the email address of the user.
Parameters:
- email: New email string.
Returns:
- void
*/
void User::setEmail(const std::string& email)
{
m_email = email;
}
/*
Function: addNotification
Description: Adds a new notification to the users notification map.
Parameters:
- notification: Pointer to the Notification object.
Returns:
- void
*/
void User::addNotification(Notification* notification)
{
m_notifications.insert(notification->getId(), notification);
if (notification)
{
m_notifications.insert(notification->getId(), notification);
}
}
/*
Function: setRole
Description: Sets the role of the user.
Parameters:
- role: New user role value.
Returns:
- void
*/
void User::setRole(util::UserType role)
{
m_type = role;
}
/*
Function: setState
Description: Sets the state (ACTIVE/INACTIVE) of the user.
Parameters:
- status: New state value.
Returns:
- void
*/
void User::setState(util::State status)
{
m_status = status;
}
void User::update(Notification* notification)
/*
Function: serialize
Description: Serializes the user into a CSV-formatted string.
Parameters:
- None
Returns:
- std::string: Serialized user record
*/
std::string User::serialize() const
{
std::ostringstream serializedUser;
serializedUser << m_id << ','
<< m_userName << ','
<< m_password << ','
<< m_name << ','
<< m_phone << ','
<< m_email << ','
<< util::getUserTypeString(m_type) << ','
<< util::getStateString(m_status);
return serializedUser.str();
}
/*
Function: deserialize
Description: Deserializes a CSV-formatted string into a User object.
Parameters:
- record: const std::string&, serialized user record
Returns:
- User*: Pointer to the deserialized User object
*/
User* User::deserialize(const std::string& record)
{
std::string id, name, username, phone, password, email;
std::string userTypeString, stateString;
std::istringstream serializedUser(record);
getline(serializedUser, id, ',');
getline(serializedUser, username, ',');
getline(serializedUser, password, ',');
getline(serializedUser, name, ',');
getline(serializedUser, phone, ',');
getline(serializedUser, email, ',');
getline(serializedUser, userTypeString, ',');
getline(serializedUser, stateString);
util::UserType userType = util::getUserType(userTypeString);
util::State status = util::getState(stateString);
return Factory::getObject<User>(id,
username,
password,
name,
phone,
email,
userType,
status);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for user serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Username,Password,Name,Phone,Email,UserType,UserStatus")
*/
std::string User::getHeaders()
{
return "ID,Username,Password,Name,Phone,Email,UserType,UserStatus";
}
@@ -1,3 +1,12 @@
/*
File: User.h
Description: Declares the User class which represents system users in the Vehicle Service Management System.
Each user has a unique ID, credentials, personal details, notifications, role type, and status.
The User class also implements the Observer interface to handle notifications.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
@@ -22,6 +31,7 @@ private:
public:
User();
User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role);
User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status);
~User();
const std::string& getId() const;
const std::string& getUserName() const;
@@ -38,8 +48,10 @@ public:
void setName(const std::string& name);
void setPhone(const std::string& phone);
void setEmail(const std::string& email);
void addNotification(Notification* notification);
void addNotification(Notification* notification) override;
void setRole(util::UserType role);
void setState(util::State status);
void update(Notification* notification) override;
std::string serialize() const;
static User* deserialize(const std::string&);
static std::string getHeaders();
};
@@ -1,3 +1,82 @@
/*
File: AuthenticationManagementService.cpp
Description: Implementation file containing the method definitions of the
AuthenticationManagementService class, including logout and
password change logic.
Author: Trenser
Date:19-May-2026
*/
#include <stdexcept>
#include "AuthenticationManagementService.h"
#include "User.h"
User* AuthenticationManagementService::m_authenticatedUser = nullptr;
/*
Function: login
Description: Authenticates a user by checking the provided username and password
against the stored users in the DataStore. If successful, sets the
authenticated user.
Parameter: const std::string& username - users username
const std::string& password - users password
Return type: bool - true if login successful, false otherwise
*/
bool AuthenticationManagementService::login(const std::string& username, const std::string& password)
{
util::Map<std::string, User*> users = m_dataStore.getUsers();
int usersMapSize = users.getSize();
for (int index = 0; index < usersMapSize; index++)
{
User* user = users.getValueAt(index);
if (username == user->getUserName())
{
if (password == user->getPassword())
{
m_authenticatedUser = user;
return true;
}
return false;
}
}
return false;
}
/*
Function: getAuthenticatedUser
Description: Retrieves the currently authenticated user.
Parameter: None
Return type: User* - pointer to the authenticated user
*/
User* AuthenticationManagementService::getAuthenticatedUser()
{
return m_authenticatedUser;
}
/*
Function: logout
Description: Logs out the currently authenticated user by clearing the
static authenticated user pointer.
Parameter: None
Return type: void
*/
void AuthenticationManagementService::logout()
{
m_authenticatedUser = nullptr;
}
/*
Function: changePassword
Description: Changes the password of the currently authenticated user.
Throws an exception if no user is logged in.
Parameter: const std::string& newPassword - new password to set
Return type: void
*/
void AuthenticationManagementService::changePassword(const std::string& newPassword)
{
if (m_authenticatedUser == nullptr)
{
throw std::runtime_error("There is no user currently logged in!");
}
m_authenticatedUser->setPassword(newPassword);
}
@@ -1,3 +1,12 @@
/*
File: AuthenticationManagementService.h
Description: Header file declaring the AuthenticationManagementService class, which manages
user authentication, login, logout, password changes, and retrieval of the
authenticated user.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "DataStore.h"
@@ -1 +1,341 @@
/*
File: InventoryManagementService.cpp
Description: Implements the InventoryManagementService class, which manages inventory
items and observer relationships within the system. Provides methods
for loading and saving inventory items from persistent storage, as well
as attaching and persisting observers for notification handling.
Author: Trenser
Date: 22-May-2026
*/
#include <stdexcept>
#include "Config.h"
#include "Enums.h"
#include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h"
#include "InventoryManagementService.h"
#include "Timestamp.h"
#include "User.h"
#include "Utility.h"
#include "Vector.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{};
/*
Function: sendLowStockAlertsToAdmins (static helper)
Description: Sends low stock alert notifications to all admin users for a given inventory item.
Parameters:
- inventoryManagementService: InventoryManagementService&, service used to send notifications
- inventoryItem: const InventoryItem*, pointer to the low-stock inventory item
- adminUsers: const util::Vector<User*>&, list of admin users to notify
Returns:
- None
*/
static void sendLowStockAlertsToAdmins(InventoryManagementService& inventoryManagementService, const InventoryItem* inventoryItem, const util::Vector<User*>& adminUsers)
{
int adminUsersSize = adminUsers.getSize();
for (int index = 0; index < adminUsersSize; index++)
{
std::string title = "Low Stock Alert";
std::string message = "The inventory item with ID " + inventoryItem->getId() + " has very low quantity in the inventory";
inventoryManagementService.sendNotification(
adminUsers[index],
title,
message
);
}
}
/*
Function: sendLowStockAlerts
Description: Sends alerts to user for inventory items with low stock
Parameters:
- None
Returns:
- None
*/
void InventoryManagementService::sendLowStockAlerts()
{
auto& inventoryItems = m_dataStore.getInventoryItems();
if (inventoryItems.isEmpty())
{
return;
}
int inventoryItemsSize = inventoryItems.getSize();
auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize();
util::Vector<User*> adminUsers;
for (int index = 0; index < usersMapSize; index++)
{
User* user = usersMap.getValueAt(index);
if (user->getUserType() == util::UserType::ADMIN)
{
adminUsers.push_back(user);
}
}
int adminUsersSize = adminUsers.getSize();
if (adminUsersSize < 1)
{
throw std::runtime_error("The system has no admins present!");
}
for (int index = 0; index < inventoryItemsSize; index++)
{
InventoryItem* inventoryItem = inventoryItems.getValueAt(index);
if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD)
{
sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers);
}
}
}
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
InventoryManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> InventoryManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadInventoryItems
Description: Loads inventory items from persistent storage into the datastore.
Uses FileManager to deserialize inventory items from the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
auto inventoryItemsMap = inventoryItemFileManager.load();
int numberOfInventoryItems = inventoryItemsMap.getSize();
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItems[inventoryItemsMap.getKeyAt(index)] = inventoryItemsMap.getValueAt(index);
}
}
/*
Function: saveInventoryItems
Description: Saves inventory items from the datastore to persistent storage.
Uses FileManager to serialize inventory items into the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
inventoryItemFileManager.save(inventoryItems);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the InventoryManagementService.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadObservers()
{
util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the InventoryManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveObservers()
{
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
}
/*
Function: addInventoryItem
Description: Creates a new inventory item using the Factory and inserts it
into the DataStore.
Parameter: const std::string& partName - name of the part
int quantity - initial quantity of the part
double price - price of the part
Return type: void
*/
void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price)
{
InventoryItem* newItem = Factory::getObject<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,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
@@ -1,6 +1,16 @@
/*
File: InventoryManagementService.h
Description: Header file declaring the InventoryManagementService class,
which manages inventory items, stock updates, and notifications
related to low stock alerts. Inherits from NotificationManagementService.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
#include "Vector.h"
#include "NotificationManagementService.h"
#include "DataStore.h"
@@ -11,14 +21,20 @@ class InventoryManagementService : public NotificationManagementService
private:
DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public:
InventoryManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, InventoryItem*> getInventoryItems();
InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price);
void removeInventoryItem(const std::string& inventoryItemID);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void sendLowStockAlerts();
void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override;
void detach(User* user) override;
void loadInventoryItems();
void saveInventoryItems();
void loadObservers();
void saveObservers();
};
@@ -1,6 +1,15 @@
/*
File: NotificationManagementService.h
Description: Declares the NotificationManagementService abstract class which defines the contract for managing notifications in the Vehicle Service Management System.
Implements the Subject interface and provides pure virtual methods for sending notifications and managing user subscriptions (attach/detach).
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Subject.h"
#include "Notification.h"
#include "User.h"
class NotificationManagementService : public Subject
@@ -10,4 +19,5 @@ public:
virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0;
virtual void attach(User* user) = 0;
virtual void detach(User* user) = 0;
virtual util::Vector<std::string> getObserverIDs() = 0;
};
@@ -1 +1,431 @@
/*
File: PaymentManagementService.cpp
Description: Implements the PaymentManagementService class which manages payment-related operations
in the Vehicle Service Management System. Provides functionality for attaching/detaching observers,
sending notifications, and issuing payment reminders based on invoice status and thresholds.
Author: Trenser
Date: 20-May-2026
*/
#include <stdexcept>
#include "Config.h"
#include "Enums.h"
#include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h"
#include "PaymentManagementService.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "Timestamp.h"
#include "User.h"
#include "Utility.h"
util::Map<std::string, User*> PaymentManagementService::m_observers{};
/*
Function: attach
Description: Attaches a user as an observer to the PaymentManagementService for receiving notifications.
Parameters:
- user: Pointer to the User object to be attached.
Returns:
- void
*/
void PaymentManagementService::attach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) == -1)
{
m_observers[userID] = user;
}
}
}
/*
Function: detach
Description: Detaches a user from the observer list of the PaymentManagementService.
Parameters:
- user: Pointer to the User object to be detached.
Returns:
- void
*/
void PaymentManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
/*
Function: sendNotification
Description: Sends a notification to a user if they are registered as an observer.
Parameters:
- user: Pointer to the User object to receive the notification.
- title: Title of the notification.
- message: Message content of the notification.
Returns:
- void
Throws:
- std::runtime_error if notification creation fails.
*/
void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
/*
Function: sendPaymentReminders
Description: Iterates through all invoices in the datastore and sends payment reminders to customers
whose invoices are pending beyond the configured threshold duration.
Parameters:
- None
Returns:
- void
*/
void PaymentManagementService::sendPaymentReminders()
{
auto& invoicesMap = m_dataStore.getInvoices();
int invoicesMapSize = invoicesMap.getSize();
for (int index = 0; index < invoicesMapSize; index++)
{
const Invoice* invoice = invoicesMap.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING)
{
util::Timestamp invoiceCreationTimestamp = invoice->getInvoiceDate();
util::Timestamp currentTimestamp;
if (util::Timestamp::getDurationInHours(invoiceCreationTimestamp, currentTimestamp) >= config::threshold::PAYMENT_REMINDER_THRESHOLD_HOURS)
{
const ServiceBooking* serviceBooking = invoice->getBooking();
if (serviceBooking)
{
User* customer = serviceBooking->getCustomer();
if (customer)
{
std::string title = "Payment Reminder";
std::string message = "Your payment for Invoice ID " + invoice->getId() + " is still pending. Please complete the payment.";
sendNotification(customer, title, message);
}
}
}
}
}
}
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
PaymentManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> PaymentManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadInvoices
Description: Loads invoices from persistent storage into the datastore.
Validates associated service bookings and inventory parts before
attaching them to each invoice. Throws exceptions if invalid IDs
are encountered.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a booking ID or part ID is invalid
*/
void PaymentManagementService::loadInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto invoicesMap = invoiceFileManager.load();
for (int invoiceIndex = 0; invoiceIndex < invoicesMap.getSize(); invoiceIndex++)
{
Invoice* invoice = invoicesMap.getValueAt(invoiceIndex);
int bookingIndex = serviceBookings.find(invoice->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
invoice->setBooking(booking);
util::Map<std::string, InventoryItem*> invoiceParts;
auto& partIDs = invoice->getPartIDs();
for (int partIndex = 0; partIndex < partIDs.getSize(); partIndex++)
{
const std::string& partID = partIDs[partIndex];
int inventoryIndex = inventoryItems.find(partID);
if (inventoryIndex == -1)
{
throw std::runtime_error("Invalid Part ID");
}
invoiceParts[partID] = inventoryItems.getValueAt(inventoryIndex);
}
invoice->setParts(invoiceParts);
invoices[invoice->getId()] = invoice;
}
}
/*
Function: saveInvoices
Description: Saves invoices from the datastore to persistent storage.
Uses FileManager to serialize invoices into the configured file.
Parameters:
- None
Returns:
- void
*/
void PaymentManagementService::saveInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
invoiceFileManager.save(invoices);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the PaymentManagementService.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
void PaymentManagementService::loadObservers()
{
util::loadObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the PaymentManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void PaymentManagementService::saveObservers()
{
util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this);
}
/*
Function: createInventoryItemsMap (static helper)
Description: Builds a map of inventory items required for a given service and adds them to the 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 totalLaborCost = 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);
util::ServiceJobStatus currentJobCardStatus = currentJobCard->getStatus();
if (currentJobCard->getBookingId() == bookingID && currentJobCardStatus != util::ServiceJobStatus::CANCELLED && currentJobCardStatus != util::ServiceJobStatus::COMPLETED)
{
throw std::runtime_error("Invoice generation failed: Not all job cards are completed for booking '" + bookingID + "'.");
}
}
for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++)
{
Service* currentService = servicesInTheBookedService.getValueAt(iterator);
if (currentService)
{
createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService);
totalLaborCost += currentService->getLaborCost();
totalPartsCost += util::calculatePartsCost(currentService);
}
}
totalServiceCost = totalLaborCost + totalPartsCost;
totalServiceCost -= (totalServiceCost * (discountPercentage / 100));
Invoice* invoice = Factory::getObject<Invoice>(bookingID, booking, util::Timestamp(), totalLaborCost, 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::PAID)
{
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentMethod(paymentMode);
invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::PAID);
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.");
}
}
/*
Function: getAllInvoice
Description: Provides access to all invoices stored in the data store.
Parameters:
- none
Returns:
- util::Map<std::string, Invoice*>&: Map of invoice IDs to invoice objects
*/
util::Map<std::string, Invoice*>& PaymentManagementService::getAllInvoices()
{
return m_dataStore.getInvoices();
}
/*
Function: confirmPayment
Description: Confirms payment for a specific invoice. Updates payment date and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::confirmPayment(const std::string& invoiceID)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex == -1)
{
throw std::runtime_error("Payment confirmation failed: invalid invoice ID.");
}
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (!invoice || invoice->getStatus() != util::PaymentStatus::PAID)
{
throw std::runtime_error("Payment confirmation failed: invoice is not awaiting confirmation.");
}
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title = "Payment Confirmed";
std::string message = "Payment Confirmed for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
}
@@ -1,3 +1,12 @@
/*
File: PaymentManagementService.h
Description: Declares the PaymentManagementService class which manages payment operations in the Vehicle Service Management System.
Provides functionality to generate invoices, retrieve customer invoices, complete payments, send payment reminders,
and handle notifications using the Observer pattern.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
@@ -13,13 +22,20 @@ class PaymentManagementService : public NotificationManagementService
private:
DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public:
PaymentManagementService() : m_dataStore(DataStore::getInstance()) {}
void generateInvoice(ServiceBooking* booking);
util::Map<std::string, Invoice*> getInvoices(const std::string& customerID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
util::Map<std::string, Invoice*>& getAllInvoices();
void confirmPayment(const std::string& invoiceID);
void sendPaymentReminders();
void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override;
void detach(User* user) override;
void loadInvoices();
void saveInvoices();
void loadObservers();
void saveObservers();
};
@@ -1,16 +1,807 @@
#include "ServiceManagementService.h"
#include "UserManagementService.h"
#include "ServiceBooking.h"
#include "Factory.h"
#include "JobCard.h"
#include "Timestamp.h"
#include "Service.h"
#include "Enums.h"
#include "InventoryItem.h"
/*
File: ServiceManagementService.cpp
Description: Implementation file containing the method definitions of the
ServiceManagementService class, including service and combo package
purchasing logic, booking creation, and notification handling.
Author: Trenser
Date:19-May-2026
*/
#include <stdexcept>
#include "AuthenticationManagementService.h"
#include "PaymentManagementService.h"
#include "ComboPackage.h"
#include "Config.h"
#include "DataStore.h"
#include "Enums.h"
#include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h"
#include "JobCard.h"
#include "NotificationManagementService.h"
#include "PaymentManagementService.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "ServiceManagementService.h"
#include "Timestamp.h"
#include "User.h"
#include "UserManagementService.h"
#include "Utility.h"
/*
Function: purchaseService
Description: Creates a new service booking for the authenticated user. Validates
service IDs, retrieves services from the DataStore, and generates a
booking. Sends a notification upon successful booking.
Parameter: const util::Vector<std::string>& serviceIDs - IDs of services to purchase
const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle
Return type: void
*/
void ServiceManagementService::purchaseService(const util::Vector<std::string>& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
AuthenticationManagementService m_authenticationManagementService;
auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (authenticatedUser == nullptr)
{
throw std::runtime_error("No user is currently logged in!");
}
auto& servicesMap = m_dataStore.getServices();
auto& serviceBookingMap = m_dataStore.getServiceBookings();
util::Map<std::string, Service*> selectedServices;
int selectedServicesCount = serviceIDs.getSize();
for (int index = 0; index < selectedServicesCount; index++)
{
int serviceIndex = servicesMap.find(serviceIDs[index]);
if (serviceIndex == -1)
{
throw std::runtime_error("Service not found!");
}
Service* service = servicesMap.getValueAt(serviceIndex);
selectedServices[service->getId()] = service;
}
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0);
if (serviceBooking == nullptr)
{
throw std::runtime_error("Failed to create service booking");
}
serviceBookingMap[serviceBooking->getId()] = serviceBooking;
std::string title = "Service Booking succeeded";
std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId();
sendNotification(authenticatedUser, title, message);
}
/*
Function: purchaseComboPackage
Description: Creates a new service booking for a combo package. Validates the combo
package ID, retrieves services from the package, and generates a booking
with the applicable discount. Sends a notification upon successful booking.
Parameter: const std::string& comboPackageID - ID of the combo package
const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle
Return type: void
*/
void ServiceManagementService::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
AuthenticationManagementService m_authenticationManagementService;
auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (authenticatedUser == nullptr)
{
throw std::runtime_error("No user is currently logged in!");
}
auto& comboPackagesMap = m_dataStore.getComboPackages();
auto& serviceBookingMap = m_dataStore.getServiceBookings();
int comboPackageIndex = comboPackagesMap.find(comboPackageID);
if (comboPackageIndex == -1)
{
throw std::runtime_error("Combo Package not found!");
}
const ComboPackage* comboPackage = comboPackagesMap[comboPackageID];
util::Map<std::string, Service*> selectedServices = comboPackage->getServices();
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, comboPackage->getDiscountPercentage());
if (serviceBooking == nullptr)
{
throw std::runtime_error("Failed to create combo package service booking");
}
serviceBookingMap[serviceBooking->getId()] = serviceBooking;
std::string title = "Combo Package Service Booking succeeded";
std::string message = "Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId();
sendNotification(authenticatedUser, title, message);
}
util::Map<std::string, User*> ServiceManagementService::m_observers{};
/*
Function: attach
Description: Attaches a user as an observer to the ServiceManagementService for receiving notifications.
Parameters:
- user: Pointer to the User object to be attached.
Returns:
- void
*/
void ServiceManagementService::attach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) == -1)
{
m_observers[userID] = user;
}
}
}
/*
Function: detach
Description: Detaches a user from the observer list of the ServiceManagementService.
Parameters:
- user: Pointer to the User object to be detached.
Returns:
- void
*/
void ServiceManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
/*
Function: sendNotification
Description: Sends a notification to a user if they are registered as an observer.
Parameters:
- user: Pointer to the User object to receive the notification.
- title: Title of the notification.
- message: Message content of the notification.
Returns:
- void
Throws:
- std::runtime_error if notification creation fails.
*/
void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
ServiceManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> ServiceManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadServices
Description: Loads services from persistent storage into the datastore.
Validates required inventory items and attaches them to each service.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an inventory item ID is invalid
*/
void ServiceManagementService::loadServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto servicesMap = serviceFileManager.load();
for (int serviceIndex = 0; serviceIndex < servicesMap.getSize(); serviceIndex++)
{
Service* service = servicesMap.getValueAt(serviceIndex);
services[service->getId()] = service;
util::Map<std::string, InventoryItem*> inventoryItemsMap;
auto& inventoryItemIDs = service->getRequiredInventoryItemIDs();
for (int inventoryItemIndex = 0; inventoryItemIndex < inventoryItemIDs.getSize(); inventoryItemIndex++)
{
const std::string& inventoryItemID = inventoryItemIDs[inventoryItemIndex];
int index = inventoryItems.find(inventoryItemID);
if (index == -1)
{
throw std::runtime_error("Invalid Inventory Item ID");
}
inventoryItemsMap[inventoryItemID] = inventoryItems.getValueAt(index);
}
service->setRequiredInventoryItems(inventoryItemsMap);
}
}
/*
Function: saveServices
Description: Saves services from the datastore to persistent storage.
Uses FileManager to serialize services into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
serviceFileManager.save(services);
}
/*
Function: loadComboPackages
Description: Loads combo packages from persistent storage into the datastore.
Validates associated services and attaches them to each package.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a service ID is invalid
*/
void ServiceManagementService::loadComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
auto& services = m_dataStore.getServices();
auto comboPackagesMap = comboPackageFileManager.load();
for (int packageIndex = 0; packageIndex < comboPackagesMap.getSize(); packageIndex++)
{
ComboPackage* comboPackage = comboPackagesMap.getValueAt(packageIndex);
util::Map<std::string, Service*> packageServices;
auto& serviceIDs = comboPackage->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
packageServices[serviceID] = services.getValueAt(serviceMapIndex);
}
comboPackage->setServices(packageServices);
comboPackages[comboPackage->getId()] = comboPackage;
}
}
/*
Function: saveComboPackages
Description: Saves combo packages from the datastore to persistent storage.
Uses FileManager to serialize combo packages into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
comboPackageFileManager.save(comboPackages);
}
/*
Function: loadServiceBookings
Description: Loads service bookings from persistent storage into the datastore.
Validates associated services, customers, and technicians before
attaching them to each booking.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a service ID, customer ID, or technician ID is invalid
- std::runtime_error if a user is not of the expected type (customer/technician)
*/
void ServiceManagementService::loadServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto bookingsMap = bookingFileManager.load();
for (int bookingIndex = 0; bookingIndex < bookingsMap.getSize(); bookingIndex++)
{
ServiceBooking* booking = bookingsMap.getValueAt(bookingIndex);
util::Map<std::string, Service*> bookingServices;
auto& serviceIDs = booking->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
bookingServices[serviceID] = services.getValueAt(serviceMapIndex);
}
booking->setServices(bookingServices);
int customerIndex = users.find(booking->getCustomerId());
if (customerIndex == -1)
{
throw std::runtime_error("Invalid Customer ID");
}
User* customer = users.getValueAt(customerIndex);
if (customer->getUserType() != util::UserType::CUSTOMER)
{
throw std::runtime_error("User is not a customer");
}
booking->setCustomer(customer);
const std::string& technicianId = booking->getAssignedTechnicianId();
if (!technicianId.empty())
{
int technicianIndex = users.find(technicianId);
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
booking->setAssignedTechnician(technician);
}
serviceBookings[booking->getId()] = booking;
}
}
/*
Function: saveServiceBookings
Description: Saves service bookings from the datastore to persistent storage.
Uses FileManager to serialize bookings into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
bookingFileManager.save(serviceBookings);
}
/*
Function: loadJobCards
Description: Loads job cards from persistent storage into the datastore.
Validates associated bookings, services, and technicians before
attaching them to each job card.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a booking ID, service ID, or technician ID is invalid
- std::runtime_error if a service does not belong to the booking
- std::runtime_error if a user is not a technician
*/
void ServiceManagementService::loadJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto jobCardsMap = jobCardFileManager.load();
for (int jobCardIndex = 0; jobCardIndex < jobCardsMap.getSize(); jobCardIndex++)
{
JobCard* jobCard = jobCardsMap.getValueAt(jobCardIndex);
int bookingIndex = serviceBookings.find(jobCard->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
jobCard->setBooking(booking);
int serviceIndex = services.find(jobCard->getServiceId());
if (serviceIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
Service* service = services.getValueAt(serviceIndex);
if (booking->getServices().find(jobCard->getServiceId()) == -1)
{
throw std::runtime_error("Service does not belong to booking");
}
jobCard->setService(service);
int technicianIndex = users.find(jobCard->getTechnicianId());
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
jobCard->setTechnician(technician);
jobCards[jobCard->getId()] = jobCard;
}
}
/*
Function: saveJobCards
Description: Saves job cards from the datastore to persistent storage.
Uses FileManager to serialize job cards into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
jobCardFileManager.save(jobCards);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the ServiceManagementService.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
void ServiceManagementService::loadObservers()
{
util::loadObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the ServiceManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveObservers()
{
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
}
/*
Function: restoreInventory
Description: Restores inventory quantities for all required items in the services associated
with a given booking. Each item's quantity is incremented by a fixed value.
Parameter: ServiceBooking* booking - Pointer to the booking whose inventory items need to be restored
Return type: void
*/
static void restoreInventory(ServiceBooking* booking)
{
const int INCREMENT_VALUE = 1;
if (!booking)
{
return;
}
const auto& services = booking->getServices();
for (int serviceIterator = 0; serviceIterator < services.getSize(); ++serviceIterator)
{
Service* service = services.getValueAt(serviceIterator);
if (!service)
{
continue;
}
const auto& items = service->getRequiredInventoryItems();
for (int InventoryIterator = 0; InventoryIterator < items.getSize(); ++InventoryIterator)
{
InventoryItem* item = items.getValueAt(InventoryIterator);
if (item)
{
item->setQuantity(item->getQuantity() + INCREMENT_VALUE);
}
}
}
}
/*
Function: processBookingCancellation
Description: Cancels jobs and updates the status of a given booking. Sends notifications to the
specified user, resets technician assignment if needed, and restores inventory items.
Parameter: ServiceBooking* booking - Pointer to the booking being cancelled
util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking
const std::string& notificationTitle - Title of the booking cancellation notification
const std::string& notificationMessage - Message body of the booking cancellation notification
User* notifyUser - User to notify about the cancellation
util::ServiceJobStatus jobCardStatus - New status to assign to associated job cards
const std::string& jobNotificationTitle - Title of the job cancellation notification
const std::string& jobNotificationMessage - Message body of the job cancellation notification
util::Map<std::string, JobCard*>& jobs - Collection of job cards to update
ServiceManagementService& currentService - Reference to the service for sending notifications
Return type: void
*/
static void processBookingCancellation(ServiceBooking* booking,
util::ServiceJobStatus newServiceBookingStatus,
const std::string& notificationTitle,
const std::string& notificationMessage,
User* notifyUser,
util::ServiceJobStatus jobCardStatus,
const std::string& jobNotificationTitle,
const std::string& jobNotificationMessage,
util::Map<std::string, JobCard*>& jobs, ServiceManagementService& currentService)
{
if (!booking || !notifyUser)
{
return;
}
for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator)
{
JobCard* jobCard = jobs.getValueAt(jobIterator);
if (jobCard && jobCard->getBookingId() == booking->getId())
{
jobCard->setStatus(jobCardStatus);
currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage);
}
}
booking->setStatus(newServiceBookingStatus);
currentService.sendNotification(notifyUser, notificationTitle, notificationMessage);
if (newServiceBookingStatus == util::ServiceJobStatus::PENDING)
{
booking->setAssignedTechnician(nullptr);
booking->setAssignedTechnicianId("");
}
restoreInventory(booking);
}
/*
Function: cancelCustomerServiceBookings
Description: Cancels all service bookings associated with a given customer or technician.
Updates booking status, resets customer/technician assignments, sends notifications,
and restocks inventory items.
Parameter: const std::string& userID - ID of the customer or technician
Return type: void
*/
void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID)
{
auto& users = m_dataStore.getUsers();
int userIndex = users.find(customerID);
if (userIndex == -1)
{
throw std::runtime_error("User not found: " + customerID);
}
User* customer = users.getValueAt(userIndex);
if (!customer)
{
throw std::runtime_error("User not found: " + customerID);
}
auto& bookings = m_dataStore.getServiceBookings();
auto& jobs = m_dataStore.getJobCards();
for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++)
{
ServiceBooking* booking = bookings.getValueAt(iteratorOne);
if (!booking)
{
continue;
}
if (booking->getCustomerId() != customerID)
{
continue;
}
if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
{
continue;
}
User* assignedTechnician = booking->getAssignedTechnician();
std::string titleToTechnician = "Customer Service Cancelled";
std::string messageToTechnician = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked.";
std::string jobTitle = "Job Cancelled";
std::string jobMessage = "The job has been cancelled. Your job card has been cancelled and the inventory has been restocked.";
processBookingCancellation(booking,
util::ServiceJobStatus::CANCELLED,
titleToTechnician, messageToTechnician, assignedTechnician,
util::ServiceJobStatus::CANCELLED,
jobTitle, jobMessage, jobs, *this
);
}
}
/*
Function: cancelTechnicianJobs
Description: Cancels all jobs assigned to a technician. Updates job status, sends notifications,
and restocks inventory items used in the service.
Parameter: const std::string& technicianID - ID of the technician
Return type: void
*/
void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID)
{
auto& users = m_dataStore.getUsers();
int userIndex = users.find(technicianID);
if (userIndex == -1)
{
throw std::runtime_error("User not found: " + technicianID);
}
User* technician = users.getValueAt(userIndex);
if (!technician)
{
throw std::runtime_error("User not found: " + technicianID);
}
auto& bookings = m_dataStore.getServiceBookings();
auto& jobs = m_dataStore.getJobCards();
for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++)
{
ServiceBooking* booking = bookings.getValueAt(iteratorOne);
if (!booking)
{
continue;
}
std::string technicianId = booking->getAssignedTechnicianId();
if (technicianId != technicianID)
{
continue;
}
if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
{
continue;
}
User* customer = booking->getCustomer();
if (!customer)
{
continue;
}
std::string title = "Technician Unavailable";
std::string message = "Your assigned technician is no longer available. Your booking has been reset to pending and we will reassign a new technician shortly.";
processBookingCancellation(booking,
util::ServiceJobStatus::PENDING,
title, message, customer,
util::ServiceJobStatus::CANCELLED,
title, message, jobs, *this
);
}
}
/*
Function: createComboPackage
Description: Creates a new combo package with two services and a discount percentage.
Validates service IDs, ensures uniqueness, and inserts the new package into the DataStore.
Parameter: const std::string& packageName - name of the combo package
const util::Vector<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
@@ -83,12 +874,16 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem->getQuantity() == 0)
if (currentInventoryItem && currentInventoryItem->getQuantity() == 0)
{
std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock.";
throw std::runtime_error(errorMessage);
}
else
}
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem)
{
int currentStockQuantity = currentInventoryItem->getQuantity();
currentInventoryItem->setQuantity(currentStockQuantity - 1);
@@ -96,11 +891,25 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const
}
currentBooking->setAssignedTechnician(selectedTechnician);
currentBooking->setAssignedTechnicianId(selectedTechnician->getId());
if (currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
currentBooking->setStatus(util::ServiceJobStatus::STARTED);
}
std::string title = "Job card created";
std::string message = "Job card created for the service and you are assigned for that.";
JobCard* jobCard = Factory::getObject<JobCard>(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp());
currentJobCards.insert(jobCard->getId(), jobCard);
sendNotification(selectedTechnician,title, message);
if (jobCard)
{
currentJobCards.insert(jobCard->getId(), jobCard);
sendNotification(selectedTechnician, title, message);
}
else
{
throw std::runtime_error("Failed to create job card.");
}
title = "Technician assigned";
message = "A technician has been assigned to your Service Booking with ID " + bookingID;
sendNotification(currentBooking->getCustomer(), title, message);
}
/*
@@ -177,10 +986,28 @@ Throws:
*/
void ServiceManagementService::removeService(const std::string& serviceID)
{
util::Map<std::string, Service*> currentServices = getServices();
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
if (currentServices.find(serviceID) != -1)
{
currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE);
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator);
if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE)
{
util::Map<std::string, Service*> currentServices = currentComboPackage->getServices();
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
auto currentService = currentServices.getValueAt(iterator);
if (currentService->getId() == serviceID)
{
currentComboPackage->setState(util::State::INACTIVE);
break;
}
}
}
}
}
else
{
@@ -238,7 +1065,7 @@ util::Map<std::string, JobCard*> ServiceManagementService::getJobCards(const std
}
/*
Function: hasAllJobCardsinServiceBookingCompleted (static helper)
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
@@ -246,14 +1073,14 @@ Parameters:
Returns:
- bool: True if all job cards are completed, False otherwise
*/
static bool hasAllJobCardsinServiceBookingCompleted(std::string bookingId, util::Map<std::string, JobCard*>& currentAssignedJobs)
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)
if (currentJob->getStatus() != util::ServiceJobStatus::COMPLETED && currentJob->getStatus() != util::ServiceJobStatus::CANCELLED)
{
return false;
}
@@ -263,18 +1090,19 @@ static bool hasAllJobCardsinServiceBookingCompleted(std::string bookingId, util:
}
/*
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.
Function: updateJobStatus
Description:
Updates the status of a job card assigned to the currently authenticated technician.
- If the job is STARTED, it moves to IN_PROGRESS.
- If the job is IN_PROGRESS, it moves to COMPLETED.
When all jobs in a service booking are completed, the booking status is updated,
an invoice is generated, and a notification is sent to the customer.
Parameters:
- jobID: std::string, ID of the job card
- jobID: const std::string&, unique identifier of the job card to update.
Returns:
- void
Throws:
- std::runtime_error if technician is not authenticated, job card not found, or job already completed
- void
*/
void ServiceManagementService::completeJob(const std::string& jobID)
void ServiceManagementService::updateJobStatus(const std::string& jobID)
{
AuthenticationManagementService authenticationManagementService;
PaymentManagementService paymentManagementService;
@@ -299,26 +1127,30 @@ void ServiceManagementService::completeJob(const std::string& jobID)
}
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{
currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS);
jobStatusUpdated = true;
}
else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{
currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
jobStatusUpdated = true;
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed. Invoice Generated.";
std::string message = "Services completed for the booking and invoice generated.";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
}
}
}
else
{
throw std::runtime_error("Failed to complete the job, some error occured or job already completed.");
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
if (!jobStatusUpdated)
{
throw std::runtime_error("Failed to complete the job, some error occured or job already completed.");
}
serviceBookingCompleted = hasAllJobCardsinServiceBookingCompleted(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed,Invoice Generated.\n";
std::string message = "Services completed for the booking and invoice generated.\n";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
}
@@ -1,3 +1,12 @@
/*
File: ServiceManagementService.h
Description: Header file declaring the ServiceManagementService class, which manages
services, combo packages, job cards, and service bookings. Inherits from
NotificationManagementService to handle notifications.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
@@ -14,6 +23,7 @@ class ServiceManagementService : public NotificationManagementService
private:
DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public:
ServiceManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, Service*> getServices();
@@ -27,12 +37,22 @@ public:
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID);
util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID);
void completeJob(const std::string& jobID);
void updateJobStatus(const std::string& jobID);
void cancelCustomerServiceBookings(const std::string& customerID);
void cancelTechnicianJobs(const std::string& technicianID);
void createComboPackage(const std::string& name, const util::Vector<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 sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override;
void detach(User* user) override;
void loadServices();
void saveServices();
void loadComboPackages();
void saveComboPackages();
void loadServiceBookings();
void saveServiceBookings();
void loadJobCards();
void saveJobCards();
void loadObservers();
void saveObservers();
};
@@ -1,5 +1,326 @@
#include "UserManagementService.h"
/*
File: UserManagementService.cpp
Description: Implementation file containing the method definitions of the
UserManagementService class, including user creation, updates,
and ensuring an admin account exists.
Author: Trenser
Date:19-May-2026
*/
#include <stdexcept>
#include "Config.h"
#include "Enums.h"
#include "Factory.h"
#include "FileManager.h"
#include "InventoryManagementService.h"
#include "Notification.h"
#include "PaymentManagementService.h"
#include "ServiceManagementService.h"
#include "User.h"
#include "UserManagementService.h"
#include "Vector.h"
#include "Validator.h"
/*
Function: ensureAdminExists
Description: Ensures that at least one admin user exists in the system.
If no admin is found, creates a default admin user using
configuration constants.
Parameter: None
Return type: void
*/
void UserManagementService::ensureAdminExists()
{
auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize();
bool isAdminFound = false;
for (int index = 0; index < usersMapSize; index++)
{
User* user = usersMap.getValueAt(index);
if (user && user->getUserType() == util::UserType::ADMIN)
{
isAdminFound = true;
break;
}
}
if (!isAdminFound)
{
createUser(
config::admin::DEFAULT_ADMIN_USERNAME,
config::admin::DEFAULT_ADMIN_NAME,
config::admin::DEFAULT_ADMIN_PASSWORD,
config::admin::DEFAULT_ADMIN_EMAIL,
config::admin::DEFAULT_ADMIN_PHONE,
util::UserType::ADMIN);
}
}
/*
Function: createUser
Description: Creates a new user with the provided details. Validates that
the username is unique, then attaches the user to relevant
management services (payment, service, inventory).
Parameter: const std::string& username - users username
const std::string& name - users name
const std::string& password - users password
const std::string& email - users email address
const std::string& phone - users phone number
util::UserType type - type of user (ADMIN, CUSTOMER, TECHNICIAN)
Return type: void
*/
void UserManagementService::createUser(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone, util::UserType type)
{
InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService;
auto& usersMap = m_dataStore.getUsers();
if (util::isUsernameDuplicate(username, usersMap))
{
throw std::runtime_error("Username already exists");
}
if (util::isEmailDuplicate(email, usersMap))
{
throw std::runtime_error("Email already exists");
}
if (util::isPhoneDuplicate(phone, usersMap))
{
throw std::runtime_error("Phone already exists");
}
User* newUser = Factory::getObject<User>(username, password, name, phone, email, type);
usersMap.insert(newUser->getId(), newUser);
paymentManagementService.attach(newUser);
serviceManagementService.attach(newUser);
if (newUser->getUserType() == util::UserType::ADMIN)
{
inventoryManagementService.attach(newUser);
}
}
/*
Function: updateUserDetails
Description: Updates the email and phone details of an existing user.
Throws an exception if the user does not exist.
Parameter: const std::string& userID - ID of the user to update
const std::string& email - new email address
const std::string& phone - new phone number
Return type: void
*/
void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone)
{
auto& usersMap = m_dataStore.getUsers();
int index = usersMap.find(userID);
if (index == -1)
{
throw std::runtime_error("User does not exist!\n");
}
User* user = usersMap.getValueAt(index);
if (email != user->getEmail())
{
if (util::isEmailDuplicate(email, usersMap))
{
throw std::runtime_error("Email already exists!\n");
}
}
if (phone != user->getPhone())
{
if (util::isPhoneDuplicate(phone, usersMap))
{
throw std::runtime_error("Phone number already exists!\n");
}
}
user->setEmail(email);
user->setPhone(phone);
}
/*
Function: getUserNotifications
Description: Retrieves all notifications associated with a given user ID.
Parameters:
- userID: The unique ID of the user whose notifications are to be retrieved.
Returns:
- util::Vector<Notification*> containing all notifications for the user.
Throws:
- std::runtime_error if no user is found with the given UserID or if the User object is invalid.
*/
util::Vector<Notification*> UserManagementService::getUserNotifications(const std::string& userID)
{
auto& usersMap = m_dataStore.getUsers();
if (usersMap.find(userID) == -1)
{
throw std::runtime_error("No user found with given UserID");
}
User* user = usersMap[userID];
if (user)
{
auto& notifications = user->getNotifications();
int numberOfNotifications = notifications.getSize();
util::Vector<Notification*> notificationsVector;
for (int index = 0; index < numberOfNotifications; index++)
{
notificationsVector.push_back(notifications.getValueAt(index));
}
return notificationsVector;
}
else
{
throw std::runtime_error("Invalid User object");
}
}
/*
Function: deleteNotification
Description: Deletes a specific notification associated with a given user ID.
Parameters:
- notificationID: The unique ID of the notification to be deleted.
- userID: The unique ID of the user whose notification is to be deleted.
Returns:
- void
Throws:
- std::runtime_error if no user is found with the given UserID or if no notification is found with the given NotificationID.
*/
void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID)
{
auto& usersMap = m_dataStore.getUsers();
if (usersMap.find(userID) == -1)
{
throw std::runtime_error("No user found with given UserID");
}
User* user = usersMap[userID];
auto& notifications = user->getNotifications();
if (notifications.find(notificationID) == -1)
{
throw std::runtime_error("No notification found with given NotificationID");
}
notifications.remove(notificationID);
}
/*
Function: loadUsers
Description: Loads users and notifications from persistent storage into the datastore.
Validates that each notifications recipient exists and attaches the
notification to the corresponding user.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a notification recipient user ID is invalid
*/
void UserManagementService::loadUsers()
{
util::FileManager<User> userFileManager(config::file::USER_FILE);
util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
auto& users = m_dataStore.getUsers();
auto usersMap = userFileManager.load();
auto notificationsMap = notificationFileManager.load();
int numberOfUsers = usersMap.getSize();
int numberOfNotifications = notificationsMap.getSize();
for (int index = 0; index < numberOfUsers; index++)
{
users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index);
}
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notificationsMap.getValueAt(index);
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = users.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = users.getValueAt(userIndex);
user->addNotification(notification);
}
}
/*
Function: saveUsers
Description: Saves users and their notifications from the datastore to persistent storage.
Collects notifications from all users into a single map before saving.
Parameters:
- None
Returns:
- void
*/
void UserManagementService::saveUsers()
{
util::FileManager<User> userFileManager(config::file::USER_FILE);
util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
auto& users = m_dataStore.getUsers();
util::Map<std::string, Notification*> notifications;
for (int userIndex = 0; userIndex < users.getSize(); userIndex++)
{
User* user = users.getValueAt(userIndex);
auto& userNotifications = user->getNotifications();
for (int notificationIndex = 0; notificationIndex < userNotifications.getSize(); notificationIndex++)
{
notifications[userNotifications.getKeyAt(notificationIndex)] =
userNotifications.getValueAt(notificationIndex);
}
}
userFileManager.save(users);
notificationFileManager.save(notifications);
}
/*
Function: getUsers
Description: Retrieves all users stored in the DataStore.
Parameter: None
Return type: util::Map<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)
{
InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService;
int index = m_dataStore.getUsers().find(userID);
if (index != -1)
{
User* user = m_dataStore.getUsers().getValueAt(index);
if (user != nullptr)
{
if (user->getUserType() == util::UserType::CUSTOMER)
{
serviceManagementService.cancelCustomerServiceBookings(userID);
}
if (user->getUserType() == util::UserType::TECHNICIAN)
{
serviceManagementService.cancelTechnicianJobs(userID);
}
user->setState(util::State::INACTIVE);
inventoryManagementService.detach(user);
paymentManagementService.detach(user);
serviceManagementService.detach(user);
}
}
}
util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type)
{
@@ -8,24 +329,10 @@ util::Map<std::string, User*> UserManagementService::getUsers(util::UserType typ
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{
User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getUserType() == type)
if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type)
{
filteredUsersMap.insert(currentUser->getId(), currentUser);
}
}
return filteredUsersMap;
}
User* UserManagementService::getUser(const std::string& userID)
{
util::Map<std::string, User*>& currentUsers = m_dataStore.getUsers();
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{
User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getId() == userID)
{
return currentUser;
}
}
return nullptr;
}
}
@@ -1,3 +1,11 @@
/*
File: UserManagementService.h
Description: Header file declaring the UserManagementService class, which manages
user creation, updates, retrieval, removal, notifications, and ensures
the existence of an admin account.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include <string>
#include "Map.h"
@@ -13,12 +21,15 @@ private:
DataStore& m_dataStore;
public:
UserManagementService() : m_dataStore(DataStore::getInstance()) {}
void createUser(const std::string& username, const std::string& password, const std::string& email, const std::string& phone, util::UserType type);
void createUser(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone, util::UserType type);
void updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone);
util::Map<std::string, User*> getUsers();
util::Map<std::string, User*> getUsers(util::UserType type);
User* getUser(const std::string& userID);
User* getUser (const std::string& userID);
void removeUser(const std::string& userID);
util::Vector<Notification*> getUserNotifications(const std::string& userID);
void deleteNotification(const std::string& notificationID, const std::string& userID);
void ensureAdminExists();
void loadUsers();
void saveUsers();
};
@@ -0,0 +1,43 @@
/*
File: Config.h
Description: Header file declaring configuration constants for the Vehicle Service System.
Includes default admin account details such as username, name, password,
email, and phone number.
Author: Trenser
Date: 21-May-2026
*/
#pragma once
namespace config
{
namespace admin
{
constexpr const char* DEFAULT_ADMIN_USERNAME = "admin";
constexpr const char* DEFAULT_ADMIN_NAME = "admin";
constexpr const char* DEFAULT_ADMIN_PASSWORD = "admin";
constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss";
constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000";
}
namespace threshold
{
constexpr int INVENTORY_LOW_STOCK_THRESHOLD = 5;
constexpr int PAYMENT_REMINDER_THRESHOLD_HOURS = 168;
}
namespace file
{
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.csv";
constexpr const char* USER_FILE = "files/User.csv";
constexpr const char* NOTIFICATION_FILE = "files/Notification.csv";
constexpr const char* SERVICE_FILE = "files/Service.csv";
constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.csv";
constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.csv";
constexpr const char* JOBCARD_FILE = "files/JobCard.csv";
constexpr const char* INVOICE_FILE = "files/Invoice.csv";
constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.csv";
constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.csv";
constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.csv";
}
}
@@ -1,3 +1,12 @@
/*
File: Enums.h
Description: Declares enumerations and utility functions for user types, payment modes, payment status,
service job status, and state management in the Vehicle Service Management System.
Provides string conversion and parsing functions for each enum type.
Author: Trenser
Date: 19-May-2026
*/
#pragma once
#include <stdexcept>
@@ -13,20 +22,24 @@ namespace util
enum class PaymentMode
{
ONLINE,
OFFLINE
OFFLINE,
NOTSET
};
enum class PaymentStatus
{
PENDING,
COMPLETED
COMPLETED,
PAID
};
enum class ServiceJobStatus
{
PENDING,
STARTED,
COMPLETED
COMPLETED,
IN_PROGRESS,
CANCELLED
};
enum class State
@@ -35,6 +48,14 @@ namespace util
INACTIVE
};
/*
Function: getUserTypeString
Description: Converts a UserType enum value to its corresponding string representation.
Parameters:
- type: UserType enum value.
Returns:
- std::string representing the UserType.
*/
inline std::string getUserTypeString(UserType type)
{
switch (type)
@@ -49,6 +70,16 @@ namespace util
throw std::invalid_argument("Invalid UserType");
}
/*
Function: getUserType
Description: Converts a string value to its corresponding UserType enum.
Parameters:
- value: std::string representing the UserType.
Returns:
- UserType enum value.
Throws:
- std::invalid_argument if the string does not match a valid UserType.
*/
inline UserType getUserType(const std::string& value)
{
if (value == "ADMIN")
@@ -66,6 +97,14 @@ namespace util
throw std::invalid_argument("Invalid UserType string");
}
/*
Function: getPaymentModeString
Description: Converts a PaymentMode enum value to its corresponding string representation.
Parameters:
- mode: PaymentMode enum value.
Returns:
- std::string representing the PaymentMode.
*/
inline std::string getPaymentModeString(PaymentMode mode)
{
switch (mode)
@@ -74,10 +113,22 @@ namespace util
return "ONLINE";
case PaymentMode::OFFLINE:
return "OFFLINE";
case PaymentMode::NOTSET:
return "NOTSET";
}
throw std::invalid_argument("Invalid PaymentMode");
}
/*
Function: getPaymentMode
Description: Converts a string value to its corresponding PaymentMode enum.
Parameters:
- value: std::string representing the PaymentMode.
Returns:
- PaymentMode enum value.
Throws:
- std::invalid_argument if the string does not match a valid PaymentMode.
*/
inline PaymentMode getPaymentMode(const std::string& value)
{
if (value == "ONLINE")
@@ -88,9 +139,21 @@ namespace util
{
return PaymentMode::OFFLINE;
}
if (value == "NOTSET")
{
return PaymentMode::NOTSET;
}
throw std::invalid_argument("Invalid PaymentMode string");
}
/*
Function: getPaymentStatusString
Description: Converts a PaymentStatus enum value to its corresponding string representation.
Parameters:
- status: PaymentStatus enum value.
Returns:
- std::string representing the PaymentStatus.
*/
inline std::string getPaymentStatusString(PaymentStatus status)
{
switch (status)
@@ -99,10 +162,22 @@ namespace util
return "PENDING";
case PaymentStatus::COMPLETED:
return "COMPLETED";
case PaymentStatus::PAID:
return "PAID";
}
throw std::invalid_argument("Invalid PaymentStatus");
}
/*
Function: getPaymentStatus
Description: Converts a string value to its corresponding PaymentStatus enum.
Parameters:
- value: std::string representing the PaymentStatus.
Returns:
- PaymentStatus enum value.
Throws:
- std::invalid_argument if the string does not match a valid PaymentStatus.
*/
inline PaymentStatus getPaymentStatus(const std::string& value)
{
if (value == "PENDING")
@@ -118,20 +193,42 @@ namespace util
throw std::invalid_argument("Invalid PaymentStatus string");
}
/*
Function: getServiceJobStatusString
Description: Converts a ServiceJobStatus enum value to its corresponding string representation.
Parameters:
- status: ServiceJobStatus enum value.
Returns:
- std::string representing the ServiceJobStatus.
*/
inline std::string getServiceJobStatusString(ServiceJobStatus status)
{
switch (status)
{
case ServiceJobStatus::PENDING:
return "PENDING";
case ServiceJobStatus::STARTED:
return "STARTED";
case ServiceJobStatus::COMPLETED:
return "COMPLETED";
case ServiceJobStatus::PENDING:
return "STARTED";
case ServiceJobStatus::CANCELLED:
return "CANCELLED";
case ServiceJobStatus::IN_PROGRESS:
return "IN_PROGRESS";
}
throw std::invalid_argument("Invalid ServiceJobStatus");
}
/*
Function: getServiceJobStatus
Description: Converts a string value to its corresponding ServiceJobStatus enum.
Parameters:
- value: std::string representing the ServiceJobStatus.
Returns:
- ServiceJobStatus enum value.
Throws:
- std::invalid_argument if the string does not match a valid ServiceJobStatus.
*/
inline ServiceJobStatus getServiceJobStatus(const std::string& value)
{
if (value == "STARTED")
@@ -142,31 +239,61 @@ namespace util
{
return ServiceJobStatus::COMPLETED;
}
if (value == "PENDING")
{
return ServiceJobStatus::PENDING;
}
if (value == "CANCELLED")
{
return ServiceJobStatus::CANCELLED;
}
if (value == "IN_PROGRESS")
{
return ServiceJobStatus::IN_PROGRESS;
}
throw std::invalid_argument("Invalid ServiceJobStatus string");
}
/*
Function: getStateString
Description: Converts a State enum value to its corresponding string representation.
Parameters:
- status: State enum value.
Returns:
- std::string representing the State.
*/
inline std::string getStateString(State status)
{
switch (status)
{
case State::ACTIVE:
return "STARTED";
return "ACTIVE";
case State::INACTIVE:
return "COMPLETED";
return "INACTIVE";
}
throw std::invalid_argument("Invalid State");
}
/*
Function: getState
Description: Converts a string value to its corresponding State enum.
Parameters:
- value: std::string representing the State.
Returns:
- State enum value.
Throws:
- std::invalid_argument if the string does not match a valid State.
*/
inline State getState(const std::string& value)
{
if (value == "ACTIVE")
{
return State::ACTIVE;
}
if (value == "COMPLETED")
if (value == "INACTIVE")
{
return State::INACTIVE;
}
throw std::invalid_argument("Invalid State string");
}
}
}
@@ -0,0 +1,109 @@
/*
File: FileHelper.h
Description: Provides utility functions for loading and saving records
from and to CSV-like text files. Ensures files are created
if missing and supports simple record persistence.
Author: Trenser
Date: 22-May-2026
*/
#pragma once
#include <fstream>
#include <string>
#include <stdexcept>
#include <direct.h>
#include "Vector.h"
namespace util
{
/*
Function: ensureDirectoryExists
Description: Creates all missing directories present in the given file path.
Iteratively parses the path and creates each directory level
using _mkdir() before file operations are performed.
Parameters:
- filePath: const std::string&, relative or absolute file path
Returns:
- void
Throws:
- None (_mkdir failures are intentionally ignored if directory already exists)
*/
inline void ensureDirectoryExists(const std::string& filePath)
{
size_t position = 0;
while ((position = filePath.find('/', position)) != std::string::npos)
{
std::string directory = filePath.substr(0, position);
if (!directory.empty())
{
(void)_mkdir(directory.c_str());
}
position++;
}
}
/*
Function: loadRecords
Description: Loads records from a given file path into a vector of strings.
Skips the header line if present. Creates the file if it does not exist.
Parameters:
- filePath: const std::string&, path to the file
Returns:
- util::Vector<std::string>: Vector containing all records (excluding header)
Throws:
- None (creates file if missing)
*/
inline util::Vector<std::string> loadRecords(const std::string& filePath)
{
util::Vector<std::string> records;
std::ifstream file(filePath);
if (!file.is_open())
{
ensureDirectoryExists(filePath);
std::ofstream newFile(filePath);
newFile.close();
file.open(filePath);
}
std::string line;
bool isHeader = true;
while (std::getline(file, line))
{
if (isHeader)
{
isHeader = false;
continue;
}
records.push_back(line);
}
return records;
}
/*
Function: saveRecords
Description: Saves records to a given file path. Overwrites existing content
and writes a header line followed by all records.
Parameters:
- filePath: const std::string&, path to the file
- records: const util::Vector<std::string>&, vector of records to save
Returns:
- void
Throws:
- std::runtime_error if the file cannot be opened for writing
*/
inline void saveRecords(const std::string& filePath, const util::Vector<std::string>& records)
{
std::ofstream file(filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + filePath);
}
file << "Values" << '\n';
int numberOfRecords = records.getSize();
for (int index = 0; index < numberOfRecords; index++)
{
file << records[index] << '\n';
}
}
}
@@ -0,0 +1,119 @@
/*
File: FileManager.h
Description: Declares and implements a generic FileManager template class for
loading and saving objects to and from files. Uses serialization
and deserialization methods defined in the object type T.
Provides persistence support for system entities such as Users,
Services, InventoryItems, etc.
Author: Trenser
Date: 22-May-2026
*/
#pragma once
#include <stdexcept>
#include <string>
#include <fstream>
#include "Vector.h"
#include "Map.h"
#include "FileHelper.h"
namespace util
{
template <typename T> using objects = util::Map<std::string, T*>;
template <typename T>
class FileManager
{
private:
std::string m_filePath;
public:
FileManager() : m_filePath("") {}
FileManager(const std::string& filePath) : m_filePath(filePath) {}
objects<T> load();
void save(const objects<T>&);
};
/*
Function: load
Description: Loads records from the file into a map of objects.
Skips the header line, deserializes each record into an object of type T,
and stores them in a map keyed by object ID.
Parameters:
- None
Returns:
- util::Map<std::string, T*> containing deserialized objects
Throws:
- std::runtime_error if deserialization fails for any record
*/
template <typename T>
objects<T> FileManager<T>::load()
{
objects<T> records;
std::ifstream file(m_filePath);
if (!file.is_open())
{
ensureDirectoryExists(m_filePath);
std::ofstream newFile(m_filePath);
newFile.close();
file.open(m_filePath);
}
util::Vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
int numberOfLines = lines.getSize();
bool isHeader = true;
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
const auto& record = lines[lineIndex];
if (isHeader)
{
isHeader = false;
continue;
}
auto object = T::deserialize(record);
if (!object)
{
throw std::runtime_error("Failed to deserialize record");
}
records[object->getId()] = object;
}
return records;
}
/*
Function: save
Description: Saves records to the file. Serializes each object of type T into a string,
writes a header line, and then writes all serialized records to the file.
Parameters:
- records: const util::Map<std::string, T*>&, map of objects to save
Returns:
- void
Throws:
- std::runtime_error if the file cannot be opened for writing
*/
template <typename T>
void FileManager<T>::save(const objects<T>& records)
{
util::Vector<std::string> lines;
lines.push_back(T::getHeaders());
int numberOfRecords = records.getSize();
for (int recordIndex = 0; recordIndex < numberOfRecords; recordIndex++)
{
const auto& record = records.getValueAt(recordIndex);
lines.push_back(record->serialize());
}
std::ofstream file(m_filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + m_filePath);
}
int numberOfLines = lines.getSize();
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
file << lines[lineIndex] << '\n';
}
}
}
@@ -34,7 +34,7 @@ namespace util
/*
* Function: read
* Description: Reads a line of text input from console into a string.
* Description: Reads a line of text input from console into a string and cleans it up.
* Parameters:
* value - reference to a string where the input will be stored
* Returns:
@@ -43,6 +43,15 @@ namespace util
inline void read(std::string& value)
{
std::getline(std::cin >> std::ws, value);
std::string cleanedValue;
for (int index = 0; index < value.length(); index++)
{
if (value[index] != ',')
{
cleanedValue += value[index];
}
}
value = cleanedValue;
}
/*
@@ -53,6 +62,7 @@ namespace util
*/
inline void pressEnter()
{
std::cout << std::endl;
system("pause");
}
}
@@ -21,4 +21,28 @@ namespace util
{
std::cout << "\x1B[2J\x1B[H" << std::flush;
}
/*
Function: truncateString
Description:
Truncates a string if its length exceeds the given maximum length.
The truncated string ends with "..." to indicate omitted characters.
Parameters:
- text: const std::string&, input string to truncate
- maxLength: size_t, maximum allowed length of the returned string
Returns:
- std::string: Original string if within limit, otherwise truncated string with "..."
*/
inline std::string truncateString(const std::string& text, size_t maxLength)
{
if (text.length() <= maxLength)
{
return text;
}
if (maxLength <= 3)
{
return std::string(maxLength, '.');
}
return text.substr(0, maxLength - 3) + "...";
}
}
@@ -0,0 +1,36 @@
/*
File: StringHelper.h
Description: Provides utility functions for extracting numeric values from strings.
Useful for parsing IDs, codes, or mixed alphanumeric inputs where
digits need to be isolated and converted into integers.
Author: Trenser
Date: 22-May-2026
*/
#include <cctype>
#include <string>
namespace util
{
/*
Function: extractNumber
Description: Extracts all digits from the given string and converts them into an integer.
Ignores non-digit characters. For example, "abc123xyz" returns 123.
Parameters:
- input: const std::string&, the input string containing digits and/or other characters
Returns:
- int: The integer value formed by concatenating all digits in the string
*/
inline int extractNumber(const std::string& input)
{
int result = 0;
for (char character : input)
{
if (std::isdigit(static_cast<unsigned char>(character)))
{
result = result * 10 + (character - '0');
}
}
return result;
}
}
@@ -0,0 +1,102 @@
/*
File: Utility.h
Description: Header file declaring utility functions used across the system
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "ComboPackage.h"
#include "DataStore.h"
#include "FileHelper.h"
#include "InventoryItem.h"
#include "NotificationManagementService.h"
#include "Service.h"
namespace util
{
/*
Function: calculatePartsCost
Description: Calculates the total cost of parts required for a given service
by summing the prices of all associated inventory items.
Parameter: const Service* service - pointer to the service object
Return type: double - total cost of required parts
*/
inline double calculatePartsCost(const Service* service)
{
double cost = 0;
auto& requiredInventoryItems = service->getRequiredInventoryItems();
int requiredInventoryItemsSize = requiredInventoryItems.getSize();
for (int index = 0; index < requiredInventoryItemsSize; index++)
{
cost += requiredInventoryItems.getValueAt(index)->getPrice();
}
return cost;
}
/*
Function: calculateComboServiceEstimatedCost
Description: Calculates the estimated total cost of a combo package by summing
the labor and parts costs of all services included in the package.
Parameter: const ComboPackage* comboPackage - pointer to the combo package object
Return type: double - estimated total cost of the combo package
*/
inline double calculateComboServiceEstimatedCost(const ComboPackage* comboPackage)
{
double cost = 0;
auto& services = comboPackage->getServices();
int servicesSize = services.getSize();
for (int index = 0; index < servicesSize; index++)
{
const Service* service = services.getValueAt(index);
cost += calculatePartsCost(service) + service->getLaborCost();
}
return cost;
}
/*
Function: loadObservers
Description: Loads observer IDs from a file and attaches the corresponding users
to the notification management service. Validates that each observer ID
exists in the datastore before attaching.
Parameters:
- filePath: const std::string&, path to the file containing observer IDs
- service: NotificationManagementService*, pointer to the notification service
- dataStore: DataStore&, reference to the datastore containing users
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
inline void loadObservers(const std::string& filePath, NotificationManagementService* service, DataStore& dataStore)
{
auto observerIDs = util::loadRecords(filePath);
auto& users = dataStore.getUsers();
for (int index = 0; index < observerIDs.getSize(); index++)
{
const std::string& observerID = observerIDs[index];
int userIndex = users.find(observerID);
if (userIndex == -1)
{
throw std::runtime_error("Invalid Observer ID");
}
service->attach(users.getValueAt(userIndex));
}
}
/*
Function: saveObservers
Description: Saves the current observer IDs from the notification management service
to a file for persistence.
Parameters:
- filePath: const std::string&, path to the file where observer IDs will be saved
- service: NotificationManagementService*, pointer to the notification service
Returns:
- void
*/
inline void saveObservers(const std::string& filePath, NotificationManagementService* service)
{
auto observerIDs = service->getObserverIDs();
util::saveRecords(filePath, observerIDs);
}
}
@@ -106,4 +106,70 @@ bool util::isPasswordValid(const std::string& password)
}
return hasUpper && hasLower && hasDigit && hasSpecial;
}
/*
* Function: isUsernameDuplicate
* Description: Checks if the given username already exists among active users.
* Parameters:
* username - string containing the username to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the username is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/
bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getUserName() == username && user->getState() == util::State::ACTIVE);
}
);
return index != -1;
}
/*
* Function: isPhoneDuplicate
* Description: Checks if the given phone number already exists among active users.
* Parameters:
* phone - string containing the phone number to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the phone number is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/
bool util::isPhoneDuplicate(const std::string& phone, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getPhone() == phone && user->getState() == util::State::ACTIVE);
}
);
return index != -1;
}
/*
* Function: isEmailDuplicate
* Description: Checks if the given email address already exists among active users.
* Parameters:
* email - string containing the email address to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the email address is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/
bool util::isEmailDuplicate(const std::string& email, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getEmail() == email && user->getState() == util::State::ACTIVE);
}
);
return index != -1;
}
@@ -9,10 +9,15 @@
#include<string>
#include<algorithm>
#include<cctype>
#include "Map.h"
#include "User.h"
namespace util
{
bool isPhoneNumberValid(const std::string&);
bool isEmailValid(const std::string&);
bool isPasswordValid(const std::string&);
bool isUsernameDuplicate(const std::string&, const util::Map<std::string, User*>&);
bool isPhoneDuplicate(const std::string&, const util::Map<std::string, User*>&);
bool isEmailDuplicate(const std::string&, const util::Map<std::string, User*>&);
}
File diff suppressed because it is too large Load Diff
@@ -1,3 +1,12 @@
/*
File: AdminMenu.h
Description: Header file declaring the AdminMenu class, which provides
administrative operations such as inventory management,
user management, service configuration, and notifications.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Controller.h"
@@ -15,10 +24,14 @@ public:
void removeInventoryItem();
void checkStockAvailability();
void assignJob();
void displayServices();
void createService();
void removeService();
void displayUsers();
void confirmPayment();
void addTechnician();
void removeUser();
void displayComboPackages();
void createComboPackages();
void removeComboPackage();
void viewNotifications();
@@ -1,58 +1,252 @@
/*
File: CustomerMenu.cpp
Description: Implementation file containing the method definitions of the
CustomerMenu class, including menu handling, service selection,
combo package booking, profile updates, and password management.
Author: Trenser
Date:19-May-2026
*/
#include <iomanip>
#include "ComboPackage.h"
#include "CustomerMenu.h"
#include "MenuHelper.h"
#include "Enums.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "User.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "Map.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "Enums.h"
#include "Timestamp.h"
#include "User.h"
#include "Validator.h"
#include "Vector.h"
/*
Function: showMenu
Description: Displays the customer menu and handles user input until logout is selected.
Parameter: None
Return type: void
*/
void CustomerMenu::showMenu()
{
bool isMenuActive = true;
while (isMenuActive)
{
try
{
int choice;
util::clear();
std::cout << "" << std::endl;
util::read(choice);
if (!handleOperation(choice))
{
isMenuActive = false;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
while (true)
{
try
{
int choice;
util::clear();
std::cout << "Customer Menu"
<< "\n1. Select a service"
<< "\n2. Select a combo package"
<< "\n3. Update Profile"
<< "\n4. Change Password"
<< "\n5. View Service History"
<< "\n6. Complete Payments"
<< "\n7. View Invoices"
<< "\n8. View Notifications"
<< "\n9. Configure Notifications"
<< "\n10. Logout"
<< "\nEnter a choice: ";
util::read(choice);
if (!handleOperation(choice))
{
break;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
}
/*
Function: handleOperation
Description: Executes the corresponding customer operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if logout
*/
bool CustomerMenu::handleOperation(int choice)
{
return false;
switch (choice)
{
case 1:
selectService();
break;
case 2:
selectComboPackage();
break;
case 3:
updateDetails();
break;
case 4:
changePassword();
break;
case 5:
viewServiceHistory();
break;
case 6:
completePayments();
break;
case 7:
viewInvoices();
break;
case 8:
viewNotifications();
break;
case 9:
configureNotifications();
break;
case 10:
logout();
return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
}
/*
Function: logout
Description: Logs out the currently authenticated customer user.
Parameter: None
Return type: void
*/
void CustomerMenu::logout()
{
m_controller.logout();
}
/*
Function: changePassword
Description: Allows the customer to change their password after validation.
Parameter: None
Return type: void
*/
void CustomerMenu::changePassword()
{
changePasswordHelper(m_controller);
}
/*
Function: updateDetails
Description: Allows the customer to update their email and phone number after validation.
Parameter: None
Return type: void
*/
void CustomerMenu::updateDetails()
{
std::string email, phone;
util::clear();
std::cout << "Update Details\n";
std::cout << "Enter new email: ";
util::read(email);
if (!util::isEmailValid(email))
{
std::cout << "Error: Email is invalid!\n";
util::pressEnter();
return;
}
std::cout << "Enter new phone: ";
util::read(phone);
if (!util::isPhoneNumberValid(phone))
{
std::cout << "Error: Phone number is invalid!\n";
util::pressEnter();
return;
}
m_controller.updateUserDetails(email, phone);
std::cout << "Profile details updated successfully\n";
util::pressEnter();
}
/*
Function: selectService
Description: Allows the customer to select a service, provide vehicle details,
and book the service through the controller.
Parameter: None
Return type: void
*/
void CustomerMenu::selectService()
{
std::string vehicleNumber, vehicleBrand, vehicleModel;
util::clear();
std::cout << "Select a Service\n";
auto services = m_controller.getServices();
if (services.isEmpty())
{
std::cout << "No services available!";
util::pressEnter();
return;
}
util::Vector<std::string> selectedServices;
const Service* selectedService = selectServiceFromServices(services);
if (selectedService == nullptr)
{
std::cout << "Failed to book service!";
util::pressEnter();
return;
}
selectedServices.push_back(selectedService->getId());
util::clear();
std::cout << "Enter Vehicle Details\n";
std::cout << "Enter vehicle number: ";
util::read(vehicleNumber);
std::cout << "Enter vehicle brand: ";
util::read(vehicleBrand);
std::cout << "Enter vehicle model: ";
util::read(vehicleModel);
m_controller.purchaseService(selectedServices, vehicleNumber, vehicleBrand, vehicleModel);
std::cout << "Service has been booked successfully";
util::pressEnter();
}
/*
Function: selectComboPackage
Description: Allows the customer to select a combo package, provide vehicle details,
and book the package through the controller.
Parameter: None
Return type: void
*/
void CustomerMenu::selectComboPackage()
{
std::string vehicleNumber, vehicleBrand, vehicleModel;
util::clear();
std::cout << "Select a Combo Package\n";
auto comboPackages = m_controller.getComboPackages();
util::Map<std::string, const ComboPackage*> activeComboPackages = filterComboPackages(comboPackages);
if (activeComboPackages.isEmpty())
{
std::cout << "No combo packages available!\n\n";
util::pressEnter();
return;
}
const ComboPackage* selectedComboPackage = selectComboPackageFromPackages(activeComboPackages);
if (selectedComboPackage == nullptr)
{
std::cout << "Failed to book combo package!\n\n";
util::pressEnter();
return;
}
std::cout << "Combo Package selected\n";
util::pressEnter();
util::clear();
std::cout << "Enter the vehicle details\n";
std::cout << "Enter vehicle number: ";
util::read(vehicleNumber);
std::cout << "Enter vehicle brand: ";
util::read(vehicleBrand);
std::cout << "Enter vehicle model: ";
util::read(vehicleModel);
m_controller.purchaseComboPackage(selectedComboPackage->getId(), vehicleNumber, vehicleBrand, vehicleModel);
std::cout << "Combo Package has been booked successfully\n\n";
util::pressEnter();
}
/*
@@ -71,16 +265,17 @@ void CustomerMenu::viewServiceHistory()
const User* currentUser = m_controller.getAuthenticatedUser();
std::string currentUserID = currentUser->getId();
util::Map<std::string, const ServiceBooking*> serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID);
std::cout << "View Service History" << std::endl;
if (serviceBookingsByCurrentUser.getSize() != 0)
{
std::cout << std::left
<< std::setw(12) << "Booking ID"
<< std::setw(15) << "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::setw(20) << "Vehicle Brand"
<< std::setw(20) << "Vehicle Number"
<< std::setw(20) << "Vehicle Model"
<< std::setw(20) << "Discount %"
<< std::setw(20) << "Status"
<< std::endl;
for (int iterator = 0; iterator < serviceBookingsByCurrentUser.getSize(); iterator++)
{
@@ -89,13 +284,13 @@ void CustomerMenu::viewServiceHistory()
? "Not Assigned"
: currentBooking->getAssignedTechnician()->getName();
std::cout << std::left
<< std::setw(12) << currentBooking->getId()
<< std::setw(15) << 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::setw(20) << currentBooking->getVehicleBrand()
<< std::setw(20) << currentBooking->getVehicleNumber()
<< std::setw(20) << currentBooking->getVehicleModel()
<< std::setw(20) << currentBooking->getDiscountPercentage()
<< std::setw(20) << util::getServiceJobStatusString(currentBooking->getStatus())
<< std::endl;
hasServiceHistory = true;
}
@@ -104,20 +299,103 @@ void CustomerMenu::viewServiceHistory()
{
std::cout << "No history available." << std::endl;
}
util::pressEnter();
}
/*
Function: completePayments
Description: Allows the customer to complete pending payments for invoices.
Validates invoice selection and payment mode before completing payment.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::completePayments()
{
util::clear();
std::cout << "Complete Payments\n";
util::Map<std::string, const Invoice*> currentInvoices = m_controller.getInvoicesByUser();
if (currentInvoices.isEmpty())
{
std::cout << "No pending invoices available for payment.\n";
util::pressEnter();
return;
}
bool hasPending = false;
for (int index = 0; index < currentInvoices.getSize(); ++index)
{
const Invoice* invoice = currentInvoices.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING)
{
hasPending = true;
break;
}
}
if (!hasPending)
{
std::cout << "No pending invoices available for payment.\n";
util::pressEnter();
return;
}
std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices, util::PaymentStatus::PENDING);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
util::pressEnter();
return;
}
util::PaymentMode paymentMode = selectPaymentMode();
m_controller.completePayment(selectedID, paymentMode);
std::cout << "Payment completed successfully.\n";
util::pressEnter();
}
/*
Function: viewInvoices
Description: Displays invoices associated with the customer by calling displayInvoices.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewInvoices()
{
util::clear();
std::cout << "View Invoices\n";
util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser();
displayInvoices(currentUserInvoices);
util::pressEnter();
}
/*
Function: viewNotifications
Description: Displays notifications for the customer and allows deletion of notifications.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewNotifications()
{
viewAndDeleteNotification(m_controller);
}
/*
Function: configureNotifications
Description: Allows the customer to configure notification preferences for payment and service management.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::configureNotifications()
{
}
bool paymentServiceNotifications = getNotificationPreference("Payment Management Service");
bool serviceManagementNotifications = getNotificationPreference("Service Management Service");
m_controller.configureNotifications(paymentServiceNotifications, serviceManagementNotifications);
util::clear();
std::cout << "Notification preferences updated successfully.\n";
util::pressEnter();
}
@@ -1,3 +1,13 @@
/*
File: CustomerMenu.h
Description: Header file declaring the CustomerMenu class, which provides
customer operations such as selecting services, booking combo
packages, updating profile details, managing payments, viewing
invoices, and configuring notifications.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Controller.h"
File diff suppressed because it is too large Load Diff
@@ -1,122 +1,184 @@
#include <iomanip>
#include "TechnicianMenu.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "JobCard.h"
#include "Enums.h"
#include "Service.h"
/*
File: TechnicianMenu.cpp
Description: Implementation file containing the method definitions of the
TechnicianMenu class, including menu handling, job completion,
notification viewing, password management, and logout logic.
Author: Trenser
Date:19-May-2026
*/
#include "Enums.h"
#include "InputHelper.h"
#include "JobCard.h"
#include "MenuHelper.h"
#include "OutputHelper.h"
#include "Service.h"
#include "TechnicianMenu.h"
#include "Validator.h"
/*
Function: showMenu
Description: Displays the technician menu in a loop until the user chooses to logout.
Handles exceptions and ensures smooth user interaction.
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::showMenu()
{
bool isMenuActive = true;
while (isMenuActive)
{
try
{
int choice;
util::clear();
std::cout << "" << std::endl;
util::read(choice);
if (!handleOperation(choice))
{
isMenuActive = false;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
}
bool TechnicianMenu::handleOperation(int choice)
{
return false;
}
/*
Function: selectJobCardToComplete (static helper)
Description: Lists all incomplete job cards assigned to the technician and allows selection by index.
Parameters:
- assignedJobCards: util::Map<std::string, const JobCard*>&, job cards assigned to the technician
- incompleteJobCards: util::Map<int, const JobCard*>&, map of incomplete job cards indexed for selection
Returns:
- std::string: ID of the selected job card, or empty string if none selected
*/
static std::string selectJobCardToComplete(util::Map<std::string, const JobCard*>& assignedJobCards, util::Map<int, const JobCard*>& incompleteJobCards)
{
int currentIndex = 1;
int choice;
bool hasIncompleteJobCard = false;
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "BookingID"
<< std::setw(12) << "JobID"
<< std::setw(20) << "ServiceName"
<< std::setw(12) << "ServiceID"
<< std::endl;
for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++)
while (true)
{
const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator);
if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED))
try
{
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);
int choice;
util::clear();
std::cout << "Technician Menu"
<< "\n1. Display My Jobs"
<< "\n2. Update Job Status"
<< "\n3. View Notifications"
<< "\n4. Change Password"
<< "\n5. Logout"
<< "\nEnter a choice: ";
util::read(choice);
if (!handleOperation(choice))
{
break;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
if (!hasIncompleteJobCard)
{
std::cout << "No pending jobs are present.\n";
return "";
}
std::cout << "Select the Job Card to complete (Index): ";
util::read(choice);
int selectedJobCardIndex = incompleteJobCards.find(choice);
if (selectedJobCardIndex != -1)
{
const JobCard* selectedJobCard = incompleteJobCards.getValueAt(selectedJobCardIndex);
return selectedJobCard->getId();
}
else
{
std::cout << "Invalid choice.\n";
return "";
}
}
/*
Function: completeJob
Description: Allows the technician to mark a selected job card as completed.
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)
{
switch (choice)
{
case 1:
displayJobs();
break;
case 2:
updateJobStatus();
break;
case 3:
viewNotifications();
break;
case 4:
changePassword();
break;
case 5:
logout();
return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
}
/*
Function: displayJobs
Description: Displays all Jobs assigned to a Technician
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::displayJobs()
{
util::clear();
std::cout << "My Jobs\n";
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
util::Map<std::string, const JobCard*> jobCards = filterStartedJobCards(assignedJobCards);
displayAllJobs(jobCards);
util::pressEnter();
}
/*
Function: updateJobStatus
Description: Allows the technician to update a selected job card.
Validates selection and updates job status through the controller.
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::completeJob()
void TechnicianMenu::updateJobStatus()
{
util::clear();
std::cout << "Update Job Status\n";
int choice;
std::string selectedJobID;
util::ServiceJobStatus selectedJobStatus = util::ServiceJobStatus::PENDING;
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 << "Select the type of job you want to update\n1.Started\n2.Inprogress\nChoice: ";
util::read(choice);
if (choice == 1)
{
selectedJobStatus = util::ServiceJobStatus::STARTED;
}
else if (choice == 2)
{
selectedJobStatus = util::ServiceJobStatus::IN_PROGRESS;
}
else
{
std::cout << "Invalid choice. Please try again.\n";
util::pressEnter();
return;
}
util::Map<std::string, const JobCard*> selectedTypeJobCard = filterJobCards(assignedJobCards, selectedJobStatus);
selectedJobID = selectJobCardToUpdate(selectedTypeJobCard, selectedJobStatus);
if (!selectedJobID.empty())
{
std::cout << "Failed to complete the job.\n";
}
else
{
m_controller.completeJob(selectedJobID);
std::cout << "Job marked as completed.\n";
m_controller.updateJobStatus(selectedJobID);
std::cout << "\nJob status updated.\n\n";
}
util::pressEnter();
}
/*
Function: viewNotifications
Description: Displays notifications for the technician and allows deletion of notifications.
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::viewNotifications()
{
viewAndDeleteNotification(m_controller);
}
/*
Function: logout
Description: Logs out the currently authenticated technician user.
Parameter: None
Return type: void
*/
void TechnicianMenu::logout()
{
m_controller.logout();
}
/*
Function: changePassword
Description: Allows the technician to change their password after validation.
Parameter: None
Return type: void
*/
void TechnicianMenu::changePassword()
{
changePasswordHelper(m_controller);
}
@@ -1,3 +1,12 @@
/*
File: TechnicianMenu.h
Description: Header file declaring the TechnicianMenu class, which provides
technician operations such as job completion, notification viewing,
password management, and logout functionality.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Controller.h"
@@ -8,6 +17,9 @@ private:
bool handleOperation(int choice);
public:
void showMenu();
void completeJob();
void displayJobs();
void updateJobStatus();
void viewNotifications();
void logout();
void changePassword();
};
@@ -1,31 +1,76 @@
#include "UserInterface.h"
/*
File: UserInterface.cpp
Description: Implementation file containing the method definitions of the
UserInterface class, including system run loop, login handling,
and customer registration logic.
Author: Trenser
Date:19-May-2026
*/
#include <iostream>
#include <stdexcept>
#include "Enums.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "User.h"
#include "UserInterface.h"
#include "Validator.h"
/*
Function: run
Description: Runs the main system loop, displaying the initial menu for login,
customer registration, or exit. Handles exceptions gracefully.
Parameter: None
Return type: void
*/
void UserInterface::run()
{
bool isMenuActive = true;
while (isMenuActive)
try
{
try
m_controller.loadSystemData();
m_controller.runSystemChecks();
bool isMenuActive = true;
while (isMenuActive)
{
int choice;
util::clear();
std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: ";
util::read(choice);
if (!handleOperation(choice))
try
{
isMenuActive = false;
int choice;
util::clear();
std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: ";
util::read(choice);
if (!handleOperation(choice))
{
isMenuActive = false;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
m_controller.saveSystemData();
}
catch (const std::invalid_argument& exception)
{
std::cout << "Exception: Invalid Argument: " << exception.what() << std::endl;
}
catch (const std::exception& exception)
{
std::cout << "Exception: " << exception.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown error occurred." << std::endl;
}
}
/*
Function: handleOperation
Description: Executes the corresponding system operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if exit
*/
bool UserInterface::handleOperation(int choice)
{
switch (choice)
@@ -46,12 +91,98 @@ bool UserInterface::handleOperation(int choice)
return true;
}
/*
Function: login
Description: Handles user login by validating credentials. Based on the authenticated
user type, navigates to the appropriate menu (Admin, Technician, Customer).
Parameter: None
Return type: void
*/
void UserInterface::login()
{
std::string username, password;
util::clear();
std::cout << "Login\n";
std::cout << "Enter username: ";
util::read(username);
std::cout << "Enter password: ";
util::read(password);
if (m_controller.login(username, password))
{
const User* authenticatedUser = m_controller.getAuthenticatedUser();
if (authenticatedUser && authenticatedUser->getState() != util::State::INACTIVE)
{
switch (authenticatedUser->getUserType())
{
case util::UserType::ADMIN:
m_adminMenu.showMenu();
break;
case util::UserType::TECHNICIAN:
m_technicianMenu.showMenu();
break;
case util::UserType::CUSTOMER:
m_customerMenu.showMenu();
break;
default:
std::cout << "\nError: Unknown user type";
break;
}
}
else if (authenticatedUser && authenticatedUser->getState() == util::State::INACTIVE)
{
std::cout << "\nError: Your account has been disabled. Please contact your Administrator.";
util::pressEnter();
}
}
else
{
std::cout << "\nError: Invalid Username or Password";
util::pressEnter();
}
}
/*
Function: registerCustomer
Description: Registers a new customer by collecting and validating details such as
username, name, email, password, and phone number. Delegates creation
to the controller.
Parameter: None
Return type: void
*/
void UserInterface::registerCustomer()
{
std::string username, name, email, phone, password;
util::clear();
std::cout << "Register Customer\n";
std::cout << "Enter username: ";
util::read(username);
std::cout << "Enter name: ";
util::read(name);
std::cout << "Enter email: ";
util::read(email);
if (!util::isEmailValid(email))
{
std::cout << "Error: Email is invalid!";
util::pressEnter();
return;
}
std::cout << "Enter password: ";
util::read(password);
if (!util::isPasswordValid(password))
{
std::cout << "Error: Password is invalid!";
util::pressEnter();
return;
}
std::cout << "Enter phone: ";
util::read(phone);
if (!util::isPhoneNumberValid(phone))
{
std::cout << "Error: Phone number is invalid!";
util::pressEnter();
return;
}
m_controller.createCustomer(username, name, password, email, phone);
std::cout << "Registration is successful";
util::pressEnter();
}
@@ -1,3 +1,13 @@
/*
File: UserInterface.h
Description: Header file declaring the UserInterface class, which provides
the main entry point for the Vehicle Service System. Handles
login, customer registration, and menu navigation for different
user roles (Admin, Technician, Customer).
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Controller.h"
#include "AdminMenu.h"
@@ -17,4 +27,4 @@ public:
void run();
void login();
void registerCustomer();
};
};