Example #1
0
        public IProcessStep NavigateForward(IWorkSession session)
        {
            try
            {
                if (!this.CanNavigateForward(session))
                {
                    throw TransactionException.BuildException(TransactionException.ErrorCode.ActionNotAvailable);
                }

                // If the navigation gets blocked by a validation issue then the navigation process must fall back to the step
                // it started on.
                var fallbackStepId = this.CurrentStepId;

                IProcessStep startingStep = this.CurrentStep;
                IProcessStep nextStep     = null;
                bool         isBlocked    = false;

                while (true)
                {
                    // Get the step history record for the starting step. This record should always exist.
                    IStepHistory stepHistory = this.TransactionHistory.GetHistoryForStep(startingStep);
                    if (stepHistory is null)
                    {
                        throw TransactionException.BuildException(TransactionException.ErrorCode.StepHistoryNotFound);
                    }

                    bool hasExecuted = stepHistory.CompletedOn.HasValue;

                    if (!hasExecuted)
                    {
                        ExecutionContext.Trace("Getting next step by executing current step.");

                        // When the step has not been executed we need to execute it to find out what the next step in the
                        // processes is because steps with conditional branching do not know the next step until execution.
                        //
                        // Additionally, any validation requirements associated with the step will be evaluated and this could
                        // result in blocking forward navigation. In this case we still update the step history to show that the
                        // step was executed.
                        var executionResult = startingStep.Execute(ExecutionContext, session, this, RequirementEvaluator);
                        nextStep  = executionResult.NextStep;
                        isBlocked = executionResult.StepIsBlocked; //validation requirements may block further advancement.

                        this.TransactionHistory.AddToHistory(this.ExecutionContext, session, nextStep, true);
                    }
                    else
                    {
                        ExecutionContext.Trace("Getting next step from step history");

                        if (stepHistory.NextStepId is null)
                        {
                            throw TransactionException.BuildException(TransactionException.ErrorCode.StepHistoryInvalid);
                        }

                        var nextStepId = this.TransactionHistory.GetHistoryById(stepHistory.NextStepId).ProcessStepId;

                        // When the step has executed then we just get the next step based on history.
                        nextStep = this.CurrentProcess.ProcessSteps.Where(r => Id == nextStepId.Id).FirstOrDefault();
                    }

                    // Stop moving forward when a UI step is found or when the step represents the last step in the process or
                    // when additional execution is blocked.
                    if (isBlocked || nextStep is null || nextStep.IsLastStep() || nextStep.Type.IsUIStep)
                    {
                        break;
                    }

                    // advance to the next process step and run through the loop again
                    startingStep = nextStep;
                }

                // When any execution in this step is blocked because of validation then the process falls back to
                // the step that was current before we started. However any items that were completed in the above loop
                if (isBlocked)
                {
                    this.CurrentStepId = fallbackStepId;
                    return(this.CurrentStep);
                }

                // save the current step to the data base.
                this.CurrentStepId = nextStep;
                this.TransactionService.SaveTransactionCurrentStep(this.ExecutionContext, this, this.CurrentStepId);

                return(this.CurrentStep);
            }
            catch (Exception ex)
            {
                throw TransactionException.BuildException(TransactionException.ErrorCode.ProcessNavigationError, ex);
            }
        }