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();
        }
예제 #3
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);
        }