Exemple #1
0
        /// <summary>
        /// Loads the drop down items.
        /// </summary>
        /// <param name="picker">The picker.</param>
        /// <param name="includeEmptyOption">if set to <c>true</c> [include empty option].</param>
        internal static void LoadDropDownItems(IStepStatusPicker picker, bool includeEmptyOption)
        {
            var selectedItems = picker.Items.Cast <ListItem>()
                                .Where(i => i.Selected)
                                .Select(i => i.Value).AsIntegerList();

            picker.Items.Clear();

            if (!picker.StepProgramId.HasValue)
            {
                return;
            }

            if (includeEmptyOption)
            {
                // add Empty option first
                picker.Items.Add(new ListItem());
            }

            var stepStatusService = new StepStatusService(new RockContext());
            var statuses          = stepStatusService.Queryable().AsNoTracking()
                                    .Where(ss =>
                                           ss.StepProgramId == picker.StepProgramId.Value &&
                                           ss.IsActive)
                                    .OrderBy(ss => ss.Order)
                                    .ThenBy(ss => ss.Name)
                                    .ToList();

            foreach (var status in statuses)
            {
                var li = new ListItem(status.Name, status.Id.ToString());
                li.Selected = selectedItems.Contains(status.Id);
                picker.Items.Add(li);
            }
        }
        /// <summary>
        /// Gets the step statuses.
        /// </summary>
        /// <returns></returns>
        private Dictionary <int, string> GetStepStatusesHtml()
        {
            if (_stepStatusesHtml != null)
            {
                return(_stepStatusesHtml);
            }

            if (_stepType == null)
            {
                return(new Dictionary <int, string>());
            }

            var rockContext       = new RockContext();
            var stepStatusService = new StepStatusService(rockContext);

            _stepStatusesHtml = stepStatusService.Queryable()
                                .AsNoTracking()
                                .Where(ss => ss.StepProgram.StepTypes.Any(st => st.Id == _stepType.Id))
                                .ToDictionary(
                ss => ss.Id,
                ss =>
                "<span class='label label-default' style='background-color: " +
                ss.StatusColorOrDefault +
                ";'>" +
                ss.Name +
                "</span>");

            return(_stepStatusesHtml);
        }
        /// <summary>
        /// Loads the Block Setting Attributes.  If a requried attribute is not found, it will display an error message
        /// and will return false.
        /// </summary>
        /// <returns>A boolean flag indicating if all block attribute properties have been loaded properly</returns>
        private bool LoadBlockSettings()
        {
            using (var rockContext = new RockContext())
            {
                var baptismStepAV    = GetAttributeValue("BaptismStepType");
                var baptismStepGuids = baptismStepAV.SplitDelimitedValues();

                var stepStatusAV    = GetAttributeValue("StepStatus");
                var stepstatusGuids = stepStatusAV.SplitDelimitedValues();

                var personAttributeGuid = GetAttributeValue("BaptismPersonAttribute").AsGuid();

                if (baptismStepAV.IsNotNullOrWhiteSpace() && baptismStepGuids.Length > 1)
                {
                    BaptismStepType = new StepTypeService(rockContext).Get(baptismStepGuids[1].AsGuid());
                }

                if (stepStatusAV.IsNotNullOrWhiteSpace() && stepstatusGuids.Length > 1)
                {
                    StepStatus = new StepStatusService(rockContext).Get(stepstatusGuids[1].AsGuid());
                }

                PersonAttribute = AttributeCache.Get(personAttributeGuid);
            }

            List <string> errors = new List <string>();

            if (BaptismStepType == null)
            {
                errors.Add("Baptism Step Type is not set.");
            }

            if (StepStatus == null)
            {
                errors.Add("Step Status is not set.");
            }

            if (PersonAttribute == null)
            {
                errors.Add("Baptism Matrix Attribute Not Set.");
            }


            if (errors.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<strong><i class='fas fa-exclamation-triangle'></i>&nbsp; Please Verify Block Settings</strong>");
                sb.Append("<ul type='disc'>");
                foreach (var error in errors)
                {
                    sb.AppendFormat("<li>{0}</li>", error);
                }
                sb.Append("</ul>");

                NotificationBoxSet(sb.ToString(), NotificationBoxType.Validation);
            }

            return(errors.Count.Equals(0));
        }
Exemple #4
0
        /// <summary>
        /// Populates the selection lists for Step Type and Step Status.
        /// </summary>
        /// <param name="filterField">The filter field.</param>
        private void PopulateStepProgramRelatedSelectionLists(FilterField filterField)
        {
            var dataContext = new RockContext();

            var programService = new StepProgramService(dataContext);

            SingleEntityPicker <StepProgram> stepProgramSingleEntityPicker = filterField.ControlsOfTypeRecursive <SingleEntityPicker <StepProgram> >().FirstOrDefault(c => c.HasCssClass("js-step-program-picker"));
            RockCheckBoxList cblStepType    = filterField.ControlsOfTypeRecursive <RockCheckBoxList>().FirstOrDefault(c => c.HasCssClass("js-step-type"));
            RockCheckBoxList _cblStepStatus = filterField.ControlsOfTypeRecursive <RockCheckBoxList>().FirstOrDefault(c => c.HasCssClass("js-step-status"));

            int?stepProgramId = stepProgramSingleEntityPicker.SelectedId;

            StepProgram stepProgram = null;

            if (stepProgramId != null)
            {
                stepProgram = programService.Get(stepProgramId.Value);
            }

            if (stepProgram != null)
            {
                // Step Type list
                cblStepType.Items.Clear();

                var stepTypeService = new StepTypeService(dataContext);

                var stepTypes = stepTypeService.Queryable().Where(x => x.StepProgramId == stepProgramId);

                foreach (var item in stepTypes)
                {
                    cblStepType.Items.Add(new ListItem(item.Name, item.Guid.ToString()));
                }

                cblStepType.Visible = cblStepType.Items.Count > 0;

                // Step Status list
                _cblStepStatus.Items.Clear();

                var stepStatusService = new StepStatusService(dataContext);

                var stepStatuses = stepStatusService.Queryable().Where(x => x.StepProgramId == stepProgramId);

                foreach (var item in stepStatuses)
                {
                    _cblStepStatus.Items.Add(new ListItem(item.Name, item.Guid.ToString()));
                }

                _cblStepStatus.Visible = _cblStepStatus.Items.Count > 0;
            }
            else
            {
                cblStepType.Visible    = false;
                _cblStepStatus.Visible = false;
            }
        }
Exemple #5
0
        /// <summary>
        /// Populates the selection lists for Step Type and Step Status.
        /// </summary>
        /// <param name="stepProgramId">The Step Program identifier.</param>
        private void PopulateStepProgramRelatedSelectionLists(int?stepProgramId)
        {
            var dataContext = new RockContext();

            var programService = new StepProgramService(dataContext);

            StepProgram stepProgram = null;

            if (stepProgramId != null)
            {
                stepProgram = programService.Get(stepProgramId.Value);
            }

            if (stepProgram != null)
            {
                // Step Type list
                _cblStepType.Items.Clear();

                var stepTypeService = new StepTypeService(dataContext);

                var stepTypes = stepTypeService.Queryable().Where(x => x.StepProgramId == stepProgramId);

                foreach (var item in stepTypes)
                {
                    _cblStepType.Items.Add(new ListItem(item.Name, item.Guid.ToString()));
                }

                _cblStepType.Visible = _cblStepType.Items.Count > 0;

                // Step Status list
                _cblStepStatus.Items.Clear();

                var stepStatusService = new StepStatusService(dataContext);

                var stepStatuses = stepStatusService.Queryable().Where(x => x.StepProgramId == stepProgramId);

                foreach (var item in stepStatuses)
                {
                    _cblStepStatus.Items.Add(new ListItem(item.Name, item.Guid.ToString()));
                }

                _cblStepStatus.Visible = _cblStepStatus.Items.Count > 0;
            }
            else
            {
                _cblStepType.Visible   = false;
                _cblStepStatus.Visible = false;
            }
        }
Exemple #6
0
        private void CreateWellKnownGuidToIdMap()
        {
            _GuidToIdMap = new Dictionary <Guid, int>();

            Dictionary <Guid, int> guidDictionary;

            var dataContext = new RockContext();

            // Add Step Types
            var stepTypeService = new StepTypeService(dataContext);

            guidDictionary = stepTypeService.Queryable().ToDictionary(k => k.Guid, v => v.Id);

            _GuidToIdMap = _GuidToIdMap.Union(guidDictionary).ToDictionary(k => k.Key, v => v.Value);

            // Add Step Statuses
            var stepStatusService = new StepStatusService(dataContext);

            guidDictionary = stepStatusService.Queryable().ToDictionary(k => k.Guid, v => v.Id);

            _GuidToIdMap = _GuidToIdMap.Union(guidDictionary).ToDictionary(k => k.Key, v => v.Value);

            // Add Person Aliases - Map Person Guid to PersonAlias.Id
            var personAliasService = new PersonAliasService(dataContext);

            var personService = new PersonService(dataContext);

            var personKnownGuids = new List <Guid>();

            personKnownGuids.Add(Constants.AlishaMarblePersonGuid);
            personKnownGuids.Add(Constants.BenJonesPersonGuid);
            personKnownGuids.Add(Constants.BillMarblePersonGuid);
            personKnownGuids.Add(Constants.BrianJonesPersonGuid);
            personKnownGuids.Add(Constants.SarahSimmonsPersonGuid);
            personKnownGuids.Add(Constants.TedDeckerPersonGuid);

            var knownPeople = personService.Queryable().Where(x => personKnownGuids.Contains(x.Guid));

            foreach (var knownPerson in knownPeople)
            {
                _GuidToIdMap.Add(knownPerson.Guid, knownPerson.PrimaryAliasId ?? 0);
            }
        }
        /// <summary>
        /// Evaluate if a specific trigger should be processed for the target entity.
        /// </summary>
        /// <param name="dataContext"></param>
        /// <param name="trigger"></param>
        /// <param name="entityGuid"></param>
        /// <param name="entityState"></param>
        /// <returns></returns>
        protected override bool ShouldProcessTrigger(RockContext dataContext, StepWorkflowTrigger trigger, Guid entityGuid, EntityState entityState)
        {
            if (trigger.TriggerType == StepWorkflowTrigger.WorkflowTriggerCondition.StatusChanged)
            {
                // Determine if this Step has transitioned between statuses that match the "To" and "From" qualifiers for this trigger.
                // If the condition does not specify a status, any status will match.
                // A new Step can only match this condition if it has a matching "To" State and a "From" State is not specified.
                if (entityState == EntityState.Added || entityState == EntityState.Modified)
                {
                    var settings = new StepWorkflowTrigger.StatusChangeTriggerSettings(trigger.TypeQualifier);

                    if ((settings.FromStatusId == null || settings.FromStatusId.Value == PreviousStepStatusId.GetValueOrDefault(-1)) &&
                        (settings.ToStatusId == null || settings.ToStatusId.Value == CurrentStepStatusId.GetValueOrDefault(-1)))
                    {
                        return(true);
                    }
                }
            }
            else if (trigger.TriggerType == StepWorkflowTrigger.WorkflowTriggerCondition.IsComplete)
            {
                // Determine if this Step has transitioned from an incomplete status to a complete status.
                // Note that adding a new Step with a complete status will satisfy this trigger.
                if (entityState == EntityState.Added || entityState == EntityState.Modified)
                {
                    var statusService = new StepStatusService(dataContext);

                    var fromStatus = statusService.Queryable().AsNoTracking().FirstOrDefault(x => x.Id == this.PreviousStepStatusId);
                    var toStatus   = statusService.Queryable().AsNoTracking().FirstOrDefault(x => x.Id == this.CurrentStepStatusId);

                    if ((fromStatus == null || !fromStatus.IsCompleteStatus) &&
                        (toStatus != null && toStatus.IsCompleteStatus))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Reads new values entered by the user for the field ( as Guid )
        /// </summary>
        /// <param name="control">Parent control that controls were added to in the CreateEditControl() method</param>
        /// <param name="configurationValues">The configuration values.</param>
        /// <returns></returns>
        public override string GetEditValue(Control control, Dictionary <string, ConfigurationValue> configurationValues)
        {
            var stepProgramStepStatusPicker = control as StepProgramStepStatusPicker;

            if (stepProgramStepStatusPicker != null)
            {
                var  rockContext     = new RockContext();
                Guid?stepProgramGuid = null;
                Guid?stepStatusGuid  = null;

                if (stepProgramStepStatusPicker.StepProgramId.HasValue)
                {
                    var stepProgram = new StepProgramService(rockContext).GetNoTracking(stepProgramStepStatusPicker.StepProgramId.Value);

                    if (stepProgram != null)
                    {
                        stepProgramGuid = stepProgram.Guid;
                    }
                }

                if (stepProgramStepStatusPicker.StepStatusId.HasValue)
                {
                    var stepStatus = new StepStatusService(rockContext).GetNoTracking(stepProgramStepStatusPicker.StepStatusId.Value);

                    if (stepStatus != null)
                    {
                        stepStatusGuid = stepStatus.Guid;
                    }
                }

                if (stepProgramGuid.HasValue || stepStatusGuid.HasValue)
                {
                    return(string.Format("{0}|{1}", stepProgramGuid, stepStatusGuid));
                }
            }

            return(null);
        }
        /// <summary>
        /// Gets the models from the delimited values.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="stepProgram">The step program.</param>
        /// <param name="stepStatus">The step status.</param>
        private void GetModelsFromAttributeValue(string value, out StepProgram stepProgram, out StepStatus stepStatus)
        {
            stepProgram = null;
            stepStatus  = null;

            ParseDelimitedGuids(value, out var stepProgramGuid, out var stepStatusGuid);

            if (stepProgramGuid.HasValue || stepStatusGuid.HasValue)
            {
                var rockContext = new RockContext();

                if (stepProgramGuid.HasValue)
                {
                    var stepProgramService = new StepProgramService(rockContext);
                    stepProgram = stepProgramService.Queryable().AsNoTracking().FirstOrDefault(sp => sp.Guid == stepProgramGuid.Value);
                }

                if (stepStatusGuid.HasValue)
                {
                    var stepStatusService = new StepStatusService(rockContext);
                    stepStatus = stepStatusService.Queryable().AsNoTracking().FirstOrDefault(sp => sp.Guid == stepStatusGuid.Value);
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void btnSave_Click(object sender, EventArgs e)
        {
            var rockContext        = GetRockContext();
            var service            = new StepService(rockContext);
            var step               = GetStep();
            var stepType           = GetStepType();
            var person             = GetPerson();
            var isPersonSelectable = IsPersonSelectable();

            // If the person is allowed to be selected and the person is missing, query for it
            if (isPersonSelectable && ppPerson.PersonId.HasValue && person == null)
            {
                var personService = new PersonService(rockContext);
                person = personService.Get(ppPerson.PersonId.Value);
            }

            // Person is the only required field for the step
            if (person == null)
            {
                ShowError("The person is required to save a step record.");
            }

            // If the step is null, then the aim is to create a new step
            var isAdd = step == null;

            if (isAdd)
            {
                step = new Step
                {
                    StepTypeId    = stepType.Id,
                    PersonAliasId = person.PrimaryAliasId.Value
                };
            }

            // Update the step properties. Person cannot be changed (only set when the step is added)
            step.StartDateTime = rdpStartDate.SelectedDate;
            step.EndDateTime   = stepType.HasEndDate ? rdpEndDate.SelectedDate : null;
            step.StepStatusId  = rsspStatus.SelectedValueAsId();

            // Update the completed date time, which is based on the start, end, and status
            if (!step.StepStatusId.HasValue)
            {
                step.CompletedDateTime = null;
            }
            else
            {
                var stepStatusService = new StepStatusService(rockContext);
                var stepStatus        = stepStatusService.Get(step.StepStatusId.Value);

                if (stepStatus == null || !stepStatus.IsCompleteStatus)
                {
                    step.CompletedDateTime = null;
                }
                else
                {
                    step.CompletedDateTime = step.EndDateTime ?? step.StartDateTime;
                }
            }

            if (!step.IsValid)
            {
                ShowError(step.ValidationResults.Select(vr => vr.ErrorMessage).ToList().AsDelimited("<br />"));
                return;
            }

            if (isAdd)
            {
                var errorMessage = string.Empty;
                var canAdd       = service.CanAdd(step, out errorMessage);

                if (!errorMessage.IsNullOrWhiteSpace())
                {
                    ShowError(errorMessage);
                    return;
                }

                if (!canAdd)
                {
                    ShowError("The step cannot be added for an unspecified reason");
                    return;
                }

                service.Add(step);
            }

            // Save the step record
            rockContext.SaveChanges();

            // Save the step attributes from the attribute controls
            step.LoadAttributes(rockContext);
            avcAttributes.GetEditValues(step);
            step.SaveAttributeValues(rockContext);

            GoToSuccessPage(step.Id);
        }
Exemple #11
0
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="serviceInstance">The service instance.</param>
        /// <param name="parameterExpression">The parameter expression.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override Expression GetExpression(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection)
        {
            var settings = new FilterSettings(selection);

            if (!settings.IsValid)
            {
                return(null);
            }

            var dataContext = ( RockContext )serviceInstance.Context;

            int stepProgramId = 0;

            var stepProgram = GetStepProgram(dataContext, settings.StepProgramGuid);

            if (stepProgram != null)
            {
                stepProgramId = stepProgram.Id;
            }

            var stepService = new StepService(dataContext);

            // Filter by Step Program
            var stepQuery = stepService.Queryable().Where(x => x.StepType.StepProgramId == stepProgramId);

            // Filter by Step Types
            if (settings.StepTypeGuids.Count() > 0)
            {
                var stepTypeService = new StepTypeService(dataContext);

                var stepTypeIds = stepTypeService.Queryable()
                                  .Where(a => settings.StepTypeGuids.Contains(a.Guid))
                                  .Select(a => a.Id).ToList();

                stepQuery = stepQuery.Where(x => stepTypeIds.Contains(x.StepTypeId));
            }

            // Filter by Step Status
            if (settings.StepStatusGuids.Count() > 0)
            {
                var stepStatusService = new StepStatusService(dataContext);

                var stepStatusIds = stepStatusService.Queryable()
                                    .Where(a => settings.StepStatusGuids.Contains(a.Guid))
                                    .Select(a => a.Id).ToList();

                stepQuery = stepQuery.Where(x => x.StepStatusId.HasValue && stepStatusIds.Contains(x.StepStatusId.Value));
            }

            // Filter by Date Started
            if (settings.StartedInPeriod != null)
            {
                var startDateRange = settings.StartedInPeriod.GetDateRange(TimePeriodDateRangeBoundarySpecifier.Exclusive);

                if (startDateRange.Start != null)
                {
                    stepQuery = stepQuery.Where(x => x.StartDateTime > startDateRange.Start.Value);
                }
                if (startDateRange.End != null)
                {
                    stepQuery = stepQuery.Where(x => x.StartDateTime < startDateRange.End.Value);
                }
            }

            // Filter by Date Completed
            if (settings.CompletedInPeriod != null)
            {
                var completedDateRange = settings.CompletedInPeriod.GetDateRange(TimePeriodDateRangeBoundarySpecifier.Exclusive);

                if (completedDateRange.Start != null)
                {
                    stepQuery = stepQuery.Where(x => x.CompletedDateTime > completedDateRange.Start.Value);
                }
                if (completedDateRange.End != null)
                {
                    stepQuery = stepQuery.Where(x => x.CompletedDateTime < completedDateRange.End.Value);
                }
            }

            // Filter by Step Campus
            if (settings.StepCampusGuids.Count() > 0)
            {
                var campusService = new CampusService(dataContext);

                var stepCampusIds = campusService.Queryable()
                                    .Where(a => settings.StepCampusGuids.Contains(a.Guid))
                                    .Select(a => a.Id).ToList();

                stepQuery = stepQuery.Where(x => x.CampusId.HasValue && stepCampusIds.Contains(x.CampusId.Value));
            }

            // Create Person Query.
            var personService = new PersonService(( RockContext )serviceInstance.Context);

            var qry = personService.Queryable()
                      .Where(p => stepQuery.Any(x => x.PersonAlias.PersonId == p.Id));

            var extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.Person>(qry, parameterExpression, "p");

            return(extractedFilterExpression);
        }
Exemple #12
0
        /// <summary>
        /// Formats the selection.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override string FormatSelection(Type entityType, string selection)
        {
            string result = "Steps taken";

            var settings = new FilterSettings(selection);

            if (!settings.IsValid)
            {
                return(result);
            }

            var dataContext = new RockContext();

            // Step Program
            var stepProgram = this.GetStepProgram(dataContext, settings.StepProgramGuid);

            if (stepProgram == null)
            {
                return(result);
            }

            // Step Types
            List <StepType> stepTypes;

            if (settings.StepTypeGuids != null)
            {
                var stepTypeService = new StepTypeService(dataContext);

                stepTypes = stepTypeService.Queryable().Where(a => settings.StepTypeGuids.Contains(a.Guid)).ToList();
            }
            else
            {
                stepTypes = new List <StepType>();
            }

            // Step Statuses
            List <StepStatus> stepStatuses;

            if (settings.StepStatusGuids != null)
            {
                var stepStatusService = new StepStatusService(dataContext);

                stepStatuses = stepStatusService.Queryable().Where(a => settings.StepStatusGuids.Contains(a.Guid)).ToList();
            }
            else
            {
                stepStatuses = new List <StepStatus>();
            }

            // Step Campuses
            List <CampusCache> stepCampuses;

            if (settings.StepCampusGuids != null)
            {
                stepCampuses = CampusCache.All().Where(a => settings.StepCampusGuids.Contains(a.Guid)).ToList();
            }
            else
            {
                stepCampuses = new List <CampusCache>();
            }

            result += string.Format(" in Program: {0}", stepProgram.Name);

            if (stepTypes.Any())
            {
                result += string.Format(", in Step: {0}", stepTypes.Select(a => a.Name).ToList().AsDelimited(","));
            }

            if (stepStatuses.Any())
            {
                result += string.Format(", with Status: {0}", stepStatuses.Select(a => a.Name).ToList().AsDelimited(","));
            }

            // Start Date
            if (settings.StartedInPeriod != null &&
                settings.StartedInPeriod.Range != TimePeriodRangeSpecifier.All)
            {
                result += string.Format(", with Date Started: {0}", settings.StartedInPeriod.GetDescription());
            }

            // Completion Date
            if (settings.CompletedInPeriod != null &&
                settings.CompletedInPeriod.Range != TimePeriodRangeSpecifier.All)
            {
                result += string.Format(", with Date Completed: {0}", settings.CompletedInPeriod.GetDescription());
            }

            if (stepCampuses.Any())
            {
                result += string.Format(", at Campus: {0}", stepCampuses.Select(a => a.Name).ToList().AsDelimited(","));
            }

            return(result);
        }
Exemple #13
0
        public void AddStepsRandomParticipationEntries()
        {
            // Get a complete set of active Step Types ordered by Program and structure order.
            var dataContext = new RockContext();

            var programService = new StepProgramService(dataContext);

            var programIdList = programService.Queryable().Where(x => x.StepTypes.Any()).OrderBy(x => x.Order).Select(x => x.Id).ToList();

            var statusService = new StepStatusService(dataContext);

            var statuses = statusService.Queryable().ToList();

            // Get a random selection of people that are not system users or specific users for which test data already exists.
            var personService = new PersonService(dataContext);

            int tedPersonAliasId = 0;

            var testPeopleIdList = new List <int> {
                tedPersonAliasId
            };

            var personQuery = personService.Queryable().Where(x => !x.IsSystem && x.LastName != "Anonymous" && !testPeopleIdList.Contains(x.Id)).Select(x => x.Id);

            var personAliasService = new PersonAliasService(dataContext);

            var personAliasIdList = personAliasService.Queryable().Where(x => personQuery.Contains(x.PersonId)).Select(x => x.Id).ToList();

            var personAliasIdQueue = new Queue <int>(personAliasIdList.GetRandomizedList(_MaxPersonCount));

            int      stepCounter   = 0;
            int      personAliasId = 0;
            int      stepProgramId = 0;
            DateTime startDateTime = RockDateTime.Now;
            DateTime newStepDateTime;
            int      campusId;
            int      maxStepTypeCount;
            int      stepsToAddCount;
            int      offsetDays;
            int      personCounter = 0;
            bool     isCompleted;

            // Loop through the set of people, adding at least 1 program and 1 step for each person.
            var rng = new Random();

            var typeService = new StepTypeService(dataContext);

            var stepTypesAll = typeService.Queryable().ToList();

            var campusList = CampusCache.All();

            StepService stepService = null;

            while (personAliasIdQueue.Any())
            {
                personAliasId = personAliasIdQueue.Dequeue();

                personCounter += 1;

                // Randomly select the Programs that this person will participate in.
                var addProgramCount = rng.Next(1, programIdList.Count + 1);

                var programsToAdd = new Queue <int>(programIdList.GetRandomizedList(addProgramCount));

                while (programsToAdd.Any())
                {
                    stepProgramId = programsToAdd.Dequeue();

                    newStepDateTime = startDateTime;

                    // Get a random campus at which the step was completed.
                    campusId = campusList.GetRandomElement().Id;

                    var stepStatuses = statusService.Queryable().Where(x => x.StepProgramId == stepProgramId).ToList();

                    maxStepTypeCount = stepTypesAll.Count(x => x.StepProgramId == stepProgramId);

                    // Randomly select a number of Steps that this person will achieve in the Program, in Step order.
                    // This creates a distribution weighted toward achievement of earlier Steps, which is the likely scenario for most Programs.
                    // Steps are added from last to first in reverse chronological order, with the last step being achieved in the current year.
                    stepsToAddCount = rng.Next(1, maxStepTypeCount);

                    Debug.Print($"Adding Steps: PersonAliasId: {personAliasId}, ProgramId={stepProgramId}, Steps={stepsToAddCount}");

                    var stepTypesToAdd = new Queue <StepType>(stepTypesAll.Take(stepsToAddCount).Reverse());

                    while (stepTypesToAdd.Any())
                    {
                        var stepTypeToAdd = stepTypesToAdd.Dequeue();

                        // If this is not the last step to be added for this person, make sure the status represents a completion.
                        if (stepTypesToAdd.Any())
                        {
                            isCompleted = true;
                        }
                        else
                        {
                            isCompleted = rng.Next(1, 100) <= _PercentChanceOfLastStepCompletion;
                        }

                        var eligibleStatuses = stepStatuses.Where(x => x.IsCompleteStatus == isCompleted).ToList();

                        // If there is no status that represents completion, allow any status.
                        if (eligibleStatuses.Count == 0)
                        {
                            eligibleStatuses = stepStatuses;
                        }

                        var newStatus = eligibleStatuses.GetRandomElement();

                        // Subtract a random number of days from the current step date to get a suitable date for the preceding step in the program.
                        offsetDays = rng.Next(1, _MaxDaysBetweenSteps);

                        newStepDateTime = newStepDateTime.AddDays(-1 * offsetDays);

                        var newStep = new Step();

                        newStep.StepTypeId = stepTypeToAdd.Id;

                        if (newStatus != null)
                        {
                            newStep.StepStatusId = newStatus.Id;
                        }

                        newStep.PersonAliasId = personAliasId;
                        newStep.CampusId      = campusId;
                        newStep.StartDateTime = newStepDateTime;

                        if (isCompleted)
                        {
                            newStep.CompletedDateTime = newStepDateTime;
                        }

                        newStep.ForeignKey = _SampleDataForeignKey;

                        if (stepService == null)
                        {
                            var stepDataContext = new RockContext();

                            stepService = new StepService(stepDataContext);
                        }

                        stepService.Add(newStep);

                        // Save a batch of records and recycle the context to speed up processing.
                        if (stepCounter % 100 == 0)
                        {
                            stepService.Context.SaveChanges();

                            stepService = null;
                        }

                        stepCounter++;
                    }
                }
            }

            Debug.Print($"--> Created {stepCounter} steps for {personCounter} people.");
        }