예제 #1
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);
        }
예제 #2
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);
        }