/// <summary> /// Update the WorkOrder's Status based on the status from (last) visit /// </summary> /// <param name="visit">The visit that will trigger the Workorder's status change</param> /// <param name="currentUserRole">The user requesting the status change</param> public void UpdateStatus(UserRole currentUserRole, Visit visit = null, bool doForce = false) { if (currentUserRole == null) { throw new ArgumentNullException(nameof(currentUserRole)); } #region check transition NotReady => VisitNeeded if (Status == WorkStatusType.NotReady) { var doStatusChange = false; // rule: check all data is complete doStatusChange = ((WorkSpecificationId > 0 || WorkSpecification != null) && (LocationId > 0 || Location != null) && (TaskInfos.Any())); // rule: No visit exists yet or last visit has status closed with redo. var closedVisit = Visits.OrderByDescending(v => v.WindowStart) .FirstOrDefault(); var isLastVisitClosedWithRedo = doForce || (closedVisit?.ResultCode != null && closedVisit.Status == VisitStatusType.Closed && closedVisit.ResultCode.Outcome == ResultCodeOutcomeType.Redo); doStatusChange = doStatusChange && (!Visits.Any() || isLastVisitClosedWithRedo); if (doStatusChange) { ChangeStatusTo(WorkStatusType.VisitNeeded, currentUserRole); } } #endregion #region check transition VisitNeeded => VisitOpen (or Aborted) if (Status == WorkStatusType.VisitNeeded) { // rule: at least one visit and last visit not in status closed var lastVisit = Visits.OrderByDescending(v => v.WindowStart) .FirstOrDefault(v => v.Status != VisitStatusType.Closed); // rule: there is an appointment booked if (lastVisit != null && lastVisit.IsAppointmentBooked) { ChangeStatusTo(WorkStatusType.VisitOpen, currentUserRole); } } #endregion #region check transition VisitOpen => Closed (or Aborted) if (Status == WorkStatusType.VisitOpen) { // (OR) rule: at least one ans last visit is closed with outcome done var lastVisit = Visits.OrderByDescending(v => v.WindowStart) .FirstOrDefault(v => v.Status == VisitStatusType.Closed); if (lastVisit?.ResultCode != null && lastVisit.ResultCode.Outcome == ResultCodeOutcomeType.Done) { ChangeStatusTo(WorkStatusType.Closed, currentUserRole); } else { // (OR) rule: last remark booking with result code abort var lastRemark = WorkOrderRemarks.OfType <BookingRemark>() .OrderByDescending(br => br.EnteredDate) .FirstOrDefault(); if (lastRemark?.ResultCode != null && lastRemark.ResultCode.Outcome == ResultCodeOutcomeType.Abort) { ChangeStatusTo(WorkStatusType.Closed, currentUserRole); } } } #endregion // TODO Alain still relevatnt? #region check if the supplied visit is the last one in workorder if (visit != null) { var lastVisit = Visits.OrderByDescending(v => v.PlannedStart).First(); if (visit.Id != lastVisit.Id) { return; } if (visit.Status == VisitStatusType.Closed) { if (visit.ResultCode == null) { throw new NotSupportedException(Translations.WorkOrderResultCodeRequired); } switch (visit.ResultCode.Outcome) { case ResultCodeOutcomeType.Abort: ChangeStatusTo(WorkStatusType.Aborted, currentUserRole); break; case ResultCodeOutcomeType.Redo: ChangeStatusTo(WorkStatusType.VisitNeeded, currentUserRole); break; case ResultCodeOutcomeType.Done: ChangeStatusTo(WorkStatusType.Closed, currentUserRole); break; } } if (visit.Status == VisitStatusType.Aborted) { ChangeStatusTo(WorkStatusType.Aborted, currentUserRole); } } #endregion }