public void TestCleanup()
        {
            var service = new AchievementAttemptService(_rockContext);

            service.DeleteRange(service.Queryable().Where(saa => _achievementIds.Contains(saa.Id) || saa.ForeignKey == KEY));
            _rockContext.SaveChanges();
        }
        public void TestCleanup()
        {
            var service = new AchievementAttemptService(_rockContext);

            service.DeleteRange(service.Queryable().Where(saa => saa.AchievementTypeId == _achievementTypeId));
            _rockContext.SaveChanges();
        }
Beispiel #3
0
        /// <summary>
        /// Gets the achiever attempt query. This is the query (not enumerated) that joins attempts of this achievement type with the
        /// achiever entities, as well as the name (<see cref="AchieverAttemptItem.AchieverName"/> that could represent the achiever
        /// in a grid or other such display.
        /// </summary>
        /// <param name="achievementTypeCache">The achievement type cache.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        public override IQueryable <AchieverAttemptItem> GetAchieverAttemptQuery(AchievementTypeCache achievementTypeCache, RockContext rockContext)
        {
            var attemptService     = new AchievementAttemptService(rockContext);
            var personAliasService = new PersonAliasService(rockContext);

            var attemptQuery     = attemptService.Queryable().Where(aa => aa.AchievementTypeId == achievementTypeCache.Id);
            var personAliasQuery = personAliasService.Queryable();

            return(attemptQuery.Join(
                       personAliasQuery,
                       aa => aa.AchieverEntityId,
                       pa => pa.Id,
                       (aa, pa) => new AchieverAttemptItem
            {
                AchievementAttempt = aa,
                Achiever = pa,
                AchieverName = pa.Person.NickName + " " + pa.Person.LastName
            }));
        }
Beispiel #4
0
        /// <summary>
        /// Processes the specified achievement type cache for the source entity.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="achievementTypeCache">The achievement type cache.</param>
        /// <param name="sourceEntity">The source entity.</param>
        /// <returns>The set of attempts that were created or updated</returns>
        public override HashSet <AchievementAttempt> Process(RockContext rockContext, AchievementTypeCache achievementTypeCache, IEntity sourceEntity)
        {
            var updatedAttempts = new HashSet <AchievementAttempt>();

            // If we cannot link the transaction to a person, then there is nothing to do
            if (!(sourceEntity is FinancialTransaction financialTransaction))
            {
                return(updatedAttempts);
            }

            // If the achievement type is not active (or null) then there is nothing to do
            if (achievementTypeCache?.IsActive != true)
            {
                return(updatedAttempts);
            }

            // If there are unmet prerequisites, then there is nothing to do
            var achievementTypeService = new AchievementTypeService(rockContext);
            var unmetPrerequisites     = achievementTypeService.GetUnmetPrerequisites(achievementTypeCache.Id, financialTransaction.AuthorizedPersonAliasId.Value);

            if (unmetPrerequisites.Any())
            {
                return(updatedAttempts);
            }

            // If the transaction is a refund, the person is empty, or less than zero amount, then there is nothing to do.
            if (null != financialTransaction.RefundDetails ||
                !financialTransaction.AuthorizedPersonAliasId.HasValue ||
                financialTransaction.AuthorizedPersonAliasId == 0 ||
                financialTransaction.TotalAmount <= 0M)
            {
                return(updatedAttempts);
            }

            // Get all of the attempts for this interaction and achievement combo, ordered by start date DESC so that
            // the most recent attempts can be found with FirstOrDefault
            var achievementAttemptService = new AchievementAttemptService(rockContext);
            var attempts = achievementAttemptService.GetOrderedAchieverAttempts(achievementAttemptService.Queryable(), achievementTypeCache, financialTransaction.AuthorizedPersonAliasId.Value);

            var mostRecentSuccess       = attempts.FirstOrDefault(saa => saa.AchievementAttemptEndDateTime.HasValue && saa.IsSuccessful);
            var overachievementPossible = achievementTypeCache.AllowOverAchievement;
            var successfulAttemptCount  = attempts.Count(saa => saa.IsSuccessful);
            var maxSuccessesAllowed     = achievementTypeCache.MaxAccomplishmentsAllowed ?? int.MaxValue;

            // If the most recent success is still open and overachievement is allowed, then update it
            if (overachievementPossible && mostRecentSuccess != null && !mostRecentSuccess.IsClosed)
            {
                UpdateOpenAttempt(mostRecentSuccess, achievementTypeCache, financialTransaction);
                updatedAttempts.Add(mostRecentSuccess);

                if (!mostRecentSuccess.IsClosed)
                {
                    // New records can only be created once the open records are all closed
                    return(updatedAttempts);
                }
            }

            // If the success count limit has been reached, then no more processing should be done
            if (successfulAttemptCount >= maxSuccessesAllowed)
            {
                return(updatedAttempts);
            }

            // Everything after the most recent success is on the table for deletion. Successes should not be
            // deleted. Everything after a success might be recalculated because of data changes.
            // Try to reuse these attempts if they match for continuity, but if the start date is changed, they
            // get deleted.
            var attemptsToDelete = attempts;

            if (mostRecentSuccess != null)
            {
                attemptsToDelete = attemptsToDelete
                                   .Where(saa => saa.AchievementAttemptStartDateTime > mostRecentSuccess.AchievementAttemptStartDateTime)
                                   .ToList();
            }

            var newAttempts = CreateNewAttempts(achievementTypeCache, financialTransaction, mostRecentSuccess);

            if (newAttempts != null && newAttempts.Any())
            {
                newAttempts = newAttempts.OrderBy(saa => saa.AchievementAttemptStartDateTime).ToList();

                foreach (var newAttempt in newAttempts)
                {
                    // Keep the old attempt if possible, otherwise add a new one
                    var existingAttempt = attemptsToDelete.FirstOrDefault(saa => saa.AchievementAttemptStartDateTime == newAttempt.AchievementAttemptStartDateTime);

                    if (existingAttempt != null)
                    {
                        attemptsToDelete.Remove(existingAttempt);
                        CopyAttempt(newAttempt, existingAttempt);
                        updatedAttempts.Add(existingAttempt);
                    }
                    else
                    {
                        newAttempt.AchieverEntityId  = financialTransaction.AuthorizedPersonAliasId.Value;
                        newAttempt.AchievementTypeId = achievementTypeCache.Id;
                        achievementAttemptService.Add(newAttempt);
                        updatedAttempts.Add(newAttempt);
                    }

                    // If this attempt was successful then make re-check the max success limit
                    if (newAttempt.IsSuccessful)
                    {
                        successfulAttemptCount++;

                        if (successfulAttemptCount >= maxSuccessesAllowed &&
                            !overachievementPossible)
                        {
                            break;
                        }
                    }
                }
            }

            if (attemptsToDelete.Any())
            {
                updatedAttempts.RemoveAll(attemptsToDelete);
                achievementAttemptService.DeleteRange(attemptsToDelete);
            }

            return(updatedAttempts);
        }
Beispiel #5
0
        /// <summary>
        /// Processes the specified achievement type cache for the source entity.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="achievementTypeCache">The achievement type cache.</param>
        /// <param name="sourceEntity">The source entity.</param>
        /// <returns>The set of attempts that were created or updated</returns>
        public override HashSet <AchievementAttempt> Process(RockContext rockContext, AchievementTypeCache achievementTypeCache, IEntity sourceEntity)
        {
            var step            = sourceEntity as Step;
            var updatedAttempts = new HashSet <AchievementAttempt>();

            // If we cannot link the step to a person, then there is nothing to do
            if (step == null)
            {
                return(updatedAttempts);
            }

            // If the achievement type is not active (or null) then there is nothing to do
            if (achievementTypeCache?.IsActive != true)
            {
                return(updatedAttempts);
            }

            // If there are unmet prerequisites, then there is nothing to do
            var achievementTypeService = new AchievementTypeService(rockContext);
            var unmetPrerequisites     = achievementTypeService.GetUnmetPrerequisites(achievementTypeCache.Id, step.PersonAliasId);

            if (unmetPrerequisites.Any())
            {
                return(updatedAttempts);
            }

            // Get all of the attempts for this program and achievement combo, ordered by start date DESC so that
            // the most recent attempts can be found with FirstOrDefault
            var achievementAttemptService = new AchievementAttemptService(rockContext);
            var attempts = achievementAttemptService.Queryable()
                           .Where(aa =>
                                  aa.AchievementTypeId == achievementTypeCache.Id &&
                                  aa.AchieverEntityId == step.PersonAliasId)
                           .ToList()
                           .OrderByDescending(aa => aa.AchievementAttemptStartDateTime)
                           .ToList();

            var mostRecentSuccess = attempts.FirstOrDefault(saa => saa.AchievementAttemptEndDateTime.HasValue && saa.IsSuccessful);

            // This component does not allow more than one success
            if (mostRecentSuccess != null)
            {
                return(updatedAttempts);
            }

            var currentAttempt = attempts.LastOrDefault();

            if (currentAttempt == null)
            {
                currentAttempt = new AchievementAttempt
                {
                    AchieverEntityId  = step.PersonAliasId,
                    AchievementTypeId = achievementTypeCache.Id
                };

                achievementAttemptService.Add(currentAttempt);
            }

            var attributeMinDate       = GetAttributeValue(achievementTypeCache, AttributeKey.StartDateTime).AsDateTime();
            var attributeMaxDate       = GetAttributeValue(achievementTypeCache, AttributeKey.EndDateTime).AsDateTime();
            var completedStepTypeDates = GetCompletedStepTypeDates(achievementTypeCache, step.PersonAliasId, attributeMinDate, attributeMaxDate);

            var stepProgram   = GetStepProgramCache(achievementTypeCache);
            var stepTypeCount = stepProgram.StepTypes.Count;

            var progress     = CalculateProgress(completedStepTypeDates.Count, stepTypeCount);
            var isSuccessful = progress >= 1m;

            currentAttempt.AchievementAttemptStartDateTime = completedStepTypeDates.Any() ? completedStepTypeDates.First() : RockDateTime.Today;
            currentAttempt.AchievementAttemptEndDateTime   = completedStepTypeDates.Any() ? completedStepTypeDates.Last() : RockDateTime.Today;
            currentAttempt.Progress     = progress;
            currentAttempt.IsClosed     = isSuccessful;
            currentAttempt.IsSuccessful = isSuccessful;

            return(updatedAttempts);
        }
        /// <summary>
        /// Executes this instance.
        /// </summary>
        /// <exception cref="System.NotImplementedException"></exception>
        public void Execute()
        {
            var achievementTypeCache = AchievementTypeCache.Get(AchievementTypeId);

            if (achievementTypeCache == null || !achievementTypeCache.IsActive)
            {
                return;
            }

            if (IsNowStarting && achievementTypeCache.AchievementStartWorkflowTypeId.HasValue)
            {
                LaunchWorkflow(achievementTypeCache.AchievementStartWorkflowTypeId.Value);
            }

            if (IsNowEnding && !IsNowSuccessful && achievementTypeCache.AchievementFailureWorkflowTypeId.HasValue)
            {
                LaunchWorkflow(achievementTypeCache.AchievementFailureWorkflowTypeId.Value);
            }

            if (IsNowSuccessful && achievementTypeCache.AchievementSuccessWorkflowTypeId.HasValue)
            {
                LaunchWorkflow(achievementTypeCache.AchievementSuccessWorkflowTypeId.Value);
            }

            if (IsNowSuccessful &&
                achievementTypeCache.AchievementStepStatusId.HasValue &&
                achievementTypeCache.AchievementStepTypeId.HasValue)
            {
                var rockContext = new RockContext();
                var achievementAttemptService = new AchievementAttemptService(rockContext);
                var achieverEntityId          = achievementAttemptService.Queryable()
                                                .AsNoTracking()
                                                .Where(aa => aa.Guid == AchievementAttemptGuid)
                                                .Select(s => s.AchieverEntityId)
                                                .FirstOrDefault();

                var personAliasEntityTypeId = EntityTypeCache.Get <PersonAlias>().Id;
                var personEntityTypeId      = EntityTypeCache.Get <Person>().Id;
                int personAliasId           = default;

                if (achievementTypeCache.AchieverEntityTypeId == personAliasEntityTypeId)
                {
                    personAliasId = achieverEntityId;
                }
                else if (achievementTypeCache.AchieverEntityTypeId == personEntityTypeId)
                {
                    var personAliasService = new PersonAliasService(rockContext);
                    personAliasId = personAliasService.Queryable()
                                    .AsNoTracking()
                                    .Where(pa => pa.PersonId == achieverEntityId)
                                    .Select(pa => pa.Id)
                                    .FirstOrDefault();
                }

                if (personAliasId != default)
                {
                    AddStep(achievementTypeCache.AchievementStepTypeId.Value,
                            achievementTypeCache.AchievementStepStatusId.Value, personAliasId);
                }
            }
        }