Compare commits

..

6 Commits

Author SHA1 Message Date
joelthomastrenser 8a3ec278ce Merged PR 1159: Vehicle Service System v1.1.0.0
**New Features**

**Payment Confirmation Workflow**
- Added support for payment confirmation by administrators.

- Introduced a new PAID payment status.

- Implemented invoice confirmation flow from PAID → COMPLETED.

- Added invoice filtering based on payment status.

- Added admin menu option to confirm customer payments.

**Technician Job Status Workflow**
- Enhanced technician job management with multi-stage status updates.

- Added support for job status transitions:

- STARTED → IN_PROGRESS

- IN_PROGRESS → COMPLETED

- Added invoice generation and customer notification upon booking completion.

- Improved job visibility by displaying current job status.

**UI Improvements**
- Improved formatting and wording in the Technician Job Status workflow.

- Standardized status labels using "In Progress".

- Improved prompts, headings, and job selection messages.

- Enhanced readability of job listings.

**Bug Fixes**
- Fixed duplicate customer notifications when an assigned technician is removed.

- Prevented creation of duplicate usernames across all user states.

- Fixed authentication conflicts caused by reuse of deleted/disabled usernames.

- Improved booking cancellation handling for customer and technician removal scenarios.

- Updated cancellation logic to correctly handle bookings in IN_PROGRESS state.

Related work items: #1797, #1798, #1807, #1808, #1809
2026-06-01 18:57:46 +05:30
Avinash Rajesh 602b538830 Merged PR 1157: Fix Duplicate Customer Notification Sent When Assigned Technician Is Removed
Fix Duplicate Customer Notification Sent When Assigned Technician Is Removed

- Refactored processBookingCancellation to simplify parameters and remove redundant notification arguments.
- Added util::UserType parameter to differentiate cancellation flows for CUSTOMER vs TECHNICIAN.
- Updated cancelCustomerServiceBookings to use processBookingCancellation with util::UserType::CUSTOMER.
- Updated cancelTechnicianJobs to use processBookingCancellation with util::UserType::TECHNICIAN.
- Enhanced booking status handling by including IN_PROGRESS status in cancellation checks.
- Ensured job cards are consistently marked CANCELLED and inventory restored.
- Fixed duplicate notification issue where customers received multiple alerts when technician was removed.

Fixes #1807

Related work items: #1807
2026-06-01 18:15:36 +05:30
Jissin Mathew 86873d2a21 Merged PR 1158: Fix Technician Job Status Update Screen UI and Formatting Issues
Fix Technician Job Status Update Screen UI and Formatting Issues

- Corrected inconsistent status label formatting: replaced "Inprogress" with "In Progress" in TechnicianMenu and MenuHelper.
- Updated headings in selectJobCardToUpdate to clearer phrasing:
  - "Select a job to mark as In Progress"
  - "Select a job to mark as Completed".
- Added spacing before and after the "No jobs available" message to improve readability and provide clear separation from headings.
- Replaced duplicated prompt "Select the Job Card to Update (Index):" with concise "Enter the job index to update:".
- Improved TechnicianMenu option display to show "In Progress" instead of "Inprogress".

Related work items: #1808
2026-06-01 18:13:34 +05:30
Jissin Mathew ce50467816 Fix Technician Job Status Update Screen UI and Formatting Issues
- Corrected inconsistent status label formatting: replaced "Inprogress" with "In Progress" in TechnicianMenu and MenuHelper.
- Updated headings in selectJobCardToUpdate to clearer phrasing:
  - "Select a job to mark as In Progress"
  - "Select a job to mark as Completed".
- Added spacing before and after the "No jobs available" message to improve readability and provide clear separation from headings.
- Replaced duplicated prompt "Select the Job Card to Update (Index):" with concise "Enter the job index to update:".
- Improved TechnicianMenu option display to show "In Progress" instead of "Inprogress".

Fixes #1808
2026-06-01 18:02:45 +05:30
joelthomastrenser 1e63b900ab Merged PR 1156: Fix: Prevent duplicate usernames across all user states
Fix: Prevent duplicate usernames across all user states

Changes:
- Updated username duplicate validation to consider all existing users.
- Prevented reuse of usernames belonging to deleted/disabled accounts.
- Fixed authentication conflicts caused by duplicate usernames.

Fixes #1809

Related work items: #1809
2026-06-01 17:44:49 +05:30
joelthomastrenser dd29c7324f Fix: Prevent duplicate usernames across all user states
Changes:
- Updated username duplicate validation to consider all existing users.
- Prevented reuse of usernames belonging to deleted/disabled accounts.
- Fixed authentication conflicts caused by duplicate usernames.

Fixes #1809
2026-06-01 17:40:27 +05:30
3 changed files with 6 additions and 8 deletions
@@ -116,15 +116,13 @@ bool util::isPasswordValid(const std::string& password)
* usersMap - map of user objects keyed by identifier * usersMap - map of user objects keyed by identifier
* Returns: * Returns:
* bool - true if the username is already in use by an active user, false otherwise * 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) bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap)
{ {
int index = usersMap.findIf( int index = usersMap.findIf(
[&](const std::string&, User* user) [&](const std::string&, User* user)
{ {
return (user->getUserName() == username && user->getState() == util::State::ACTIVE); return (user->getUserName() == username);
} }
); );
return index != -1; return index != -1;
@@ -736,7 +736,7 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
util::Map<int, const JobCard* > incompleteJobCards; util::Map<int, const JobCard* > incompleteJobCards;
if (assignedJobCards.getSize() == 0) if (assignedJobCards.getSize() == 0)
{ {
std::cout << "No jobs available.\n\n"; std::cout << "\nNo jobs available.\n\n";
return ""; return "";
} }
int currentIndex = 1; int currentIndex = 1;
@@ -744,12 +744,12 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
if (selectedJobStatusType == util::ServiceJobStatus::STARTED) if (selectedJobStatusType == util::ServiceJobStatus::STARTED)
{ {
util::clear(); util::clear();
std::cout << "Select a job to update to Inprogress\n"; std::cout << "Select a job to mark as In Progress\n";
} }
else if (selectedJobStatusType == util::ServiceJobStatus::IN_PROGRESS) else if (selectedJobStatusType == util::ServiceJobStatus::IN_PROGRESS)
{ {
util::clear(); util::clear();
std::cout << "Select a job to update to Completed\n"; std::cout << "Select a job to mark as Completed\n";
} }
else else
{ {
@@ -780,7 +780,7 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
incompleteJobCards.insert(currentIndex++, currentJobCard); incompleteJobCards.insert(currentIndex++, currentJobCard);
} }
} }
std::cout << "Select the Job Card to Update (Index): "; std::cout << "Enter the job index to update: ";
util::read(choice); util::read(choice);
int selectedJobCardIndex = incompleteJobCards.find(choice); int selectedJobCardIndex = incompleteJobCards.find(choice);
if (selectedJobCardIndex != -1) if (selectedJobCardIndex != -1)
@@ -121,7 +121,7 @@ void TechnicianMenu::updateJobStatus()
std::string selectedJobID; std::string selectedJobID;
util::ServiceJobStatus selectedJobStatus = util::ServiceJobStatus::PENDING; util::ServiceJobStatus selectedJobStatus = util::ServiceJobStatus::PENDING;
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser(); util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
std::cout << "Select the type of job you want to update\n1.Started\n2.Inprogress\nChoice: "; std::cout << "Select the type of job you want to update:\n1.Started\n2.In Progress\nChoice: ";
util::read(choice); util::read(choice);
if (choice == 1) if (choice == 1)
{ {