Fix Completing a Job Throws an Exception

Changes:

- Refactored ServiceManagementService::updateJobStatus() to use tracked
  job card references instead of raw pointers, ensuring consistent state
  updates.
- Added proper null checks and error handling for current job retrieval
  to prevent unexpected termination.
- Updated logic to mark tracked job records as MODIFIED when status
  transitions occur (STARTED → IN_PROGRESS, IN_PROGRESS → COMPLETED).
- Simplified control flow and indentation for better readability and
  maintainability.

Fixes #2076
This commit is contained in:
Jissin Mathew
2026-06-17 17:01:34 +05:30
parent 4243f4e43f
commit bb0d186b62
2 changed files with 42 additions and 37 deletions
@@ -220,6 +220,11 @@ void DataStore::refreshCache(util::Map<std::string, TrackedRecord<TObject>>& cac
if (oldIndex != -1) if (oldIndex != -1)
{ {
TrackedRecord<TObject>& oldRecord = oldCache.getValueAt(oldIndex); TrackedRecord<TObject>& oldRecord = oldCache.getValueAt(oldIndex);
if (oldRecord.state == RecordState::MODIFIED)
{
cache.insert(id, oldRecord);
continue;
}
*oldRecord.data = *refreshedRecord.data; *oldRecord.data = *refreshedRecord.data;
oldRecord.slotIndex = refreshedRecord.slotIndex; oldRecord.slotIndex = refreshedRecord.slotIndex;
oldRecord.state = refreshedRecord.state; oldRecord.state = refreshedRecord.state;
@@ -880,44 +880,44 @@ Returns:
void ServiceManagementService::updateJobStatus(const std::string& jobID) void ServiceManagementService::updateJobStatus(const std::string& jobID)
{ {
DataStoreLockGuard lock(m_dataStore); DataStoreLockGuard lock(m_dataStore);
AuthenticationManagementService authenticationManagementService; AuthenticationManagementService authenticationManagementService;
PaymentManagementService paymentManagementService; PaymentManagementService paymentManagementService;
bool jobStatusUpdated = false, serviceBookingCompleted; bool jobStatusUpdated = false, serviceBookingCompleted;
JobCard* currentJob; User* currentTechnician = authenticationManagementService.getAuthenticatedUser();
User* currentTechnician = authenticationManagementService.getAuthenticatedUser(); if (currentTechnician == nullptr)
if (currentTechnician == nullptr) {
{ throw std::runtime_error("Unable to fetch current technician.");
throw std::runtime_error("Unable to fetch current technician."); }
} util::Map<std::string, JobCard*> currentAssignedJobs = getJobCards(currentTechnician->getId());
util::Map<std::string, JobCard*> currentAssignedJobs = getJobCards(currentTechnician->getId()); if (currentAssignedJobs.getSize() == 0)
if (currentAssignedJobs.getSize() == 0) {
{ throw std::runtime_error("No job cards assigned to the technician.");
throw std::runtime_error("No job cards assigned to the technician."); }
}
auto& trackedJobCards = m_dataStore.getJobCards(); auto& trackedJobCards = m_dataStore.getJobCards();
auto& trackedServiceBookings = m_dataStore.getServiceBookings(); auto& trackedServiceBookings = m_dataStore.getServiceBookings();
if (currentAssignedJobs.find(jobID) != -1) if (currentAssignedJobs.find(jobID) != -1)
{ {
int jobIndex = trackedJobCards.find(jobID); int jobIndex = trackedJobCards.find(jobID);
if (jobIndex == -1) if (jobIndex == -1)
{ {
throw std::runtime_error("Unable to fetch current job."); throw std::runtime_error("Unable to fetch current job.");
} }
currentJob = currentAssignedJobs.getValueAt(currentAssignedJobs.find(jobID)); auto& trackedCurrentJob = trackedJobCards.getValueAt(jobIndex);
if (currentJob == nullptr) JobCard* currentJob = trackedCurrentJob.data;
{ if (currentJob == nullptr)
throw std::runtime_error("Unable to fetch current job."); {
} throw std::runtime_error("Unable to fetch current job.");
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) }
{ if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS); {
trackedJobCards.getValueAt(jobIndex).state = RecordState::MODIFIED; currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS);
jobStatusUpdated = true; trackedCurrentJob.state = RecordState::MODIFIED;
} jobStatusUpdated = true;
}
else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS) else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{ {
currentJob->setStatus(util::ServiceJobStatus::COMPLETED); currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
trackedJobCards.getValueAt(jobIndex).state = RecordState::MODIFIED; trackedCurrentJob.state = RecordState::MODIFIED;
jobStatusUpdated = true; jobStatusUpdated = true;
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs); serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted) if (serviceBookingCompleted)
@@ -931,15 +931,15 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID)
sendNotification(currentJob->getBooking()->getCustomer(), title, message); sendNotification(currentJob->getBooking()->getCustomer(), title, message);
} }
} }
} }
else else
{ {
throw std::runtime_error("Failed to update job status. Job may already be completed."); throw std::runtime_error("Failed to update job status. Job may already be completed.");
} }
if (!jobStatusUpdated) if (!jobStatusUpdated)
{ {
throw std::runtime_error("Failed to update job status. Job may already be completed."); throw std::runtime_error("Failed to update job status. Job may already be completed.");
} }
m_dataStore.saveJobCards(); m_dataStore.saveJobCards();
m_dataStore.saveServiceBookings(); m_dataStore.saveServiceBookings();
} }