Exemplo n.º 1
0
        /// <summary>
        /// Validates the expression.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="expr">The expr.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public ValidationResult ValidateExpression(string key, string expr, PromotionContext context)
        {
            Dictionary <string, object> dic = new Dictionary <string, object>();

            dic.Add("PromotionContext", context);
            return(ValidateExpression(key, expr, dic));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Evaluates the promotions.
        /// </summary>
        /// <param name="useCache">if set to <c>true</c> [use cache].</param>
        /// <param name="context">The context.</param>
        /// <param name="filter">The filter.</param>
        /// <returns>Collection of promotions that were applied. Look inside PromotionContext for actual rewards and for items that have been affected by these promotions.</returns>
        public PromotionItemCollection EvaluatePromotions(bool useCache, PromotionContext context, PromotionFilter filter)
        {
            MarketingHelper         helper = GetMarketingHelper(useCache);
            PromotionItemCollection dto    = new PromotionItemCollection(helper);

            // Remove current customer promotion history if we opted to not use cache (which happens during checkout)
            if (!useCache)
            {
                string cacheKey = MarketingCache.CreateCacheKey("MarketingHelper-customer", context.CustomerId.ToString());
                MarketingCache.Remove(cacheKey);
            }

            return(EvaluatePromotions(context, dto, filter));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Returns customer segments for specified customer or organization.
        /// </summary>
        /// <param name="context">The context. Should include ContextConstants.CustomerProfile of type ProfileBase</param>
        /// <param name="customerPrincipalId">The customer principal id.</param>
        /// <param name="organizationPrincipalId">The organization principal id.</param>
        /// <returns>int list of customer segment ids</returns>
        public List <int> GetCustomerSegments(Dictionary <string, object> context, Guid customerPrincipalId, Guid organizationPrincipalId)
        {
            List <int>      segments    = new List <int>();
            MarketingHelper helper      = GetMarketingHelper(true);
            SegmentDto      segmentsDto = helper.Segments;

            PromotionContext promotionContext = new PromotionContext(context, null, null);

            // Cycle through customer segments
            foreach (SegmentDto.SegmentRow segmentRow in segmentsDto.Segment)
            {
                bool includeSegment = false;
                bool excludeSegment = false;

                // Check if profile is directly specified in the members tables
                foreach (SegmentDto.SegmentMemberRow memberRow in segmentRow.GetSegmentMemberRows())
                {
                    if (memberRow.PrincipalId == customerPrincipalId || memberRow.PrincipalId == organizationPrincipalId)
                    {
                        if (memberRow.Exclude)
                        {
                            excludeSegment = true;
                            break;
                        }
                        else
                        {
                            includeSegment = true;
                            break;
                        }
                    }
                }

                // if explicitely excluded, skip the segment
                if (excludeSegment)
                {
                    continue;
                }

                // Validate expressions, if any of the expression is met, user is part of the group
                foreach (SegmentDto.SegmentConditionRow condition in segmentRow.GetSegmentConditionRows())
                {
                    ExpressionDto.ExpressionRow expressionRow = helper.Expressions.Expression.FindByExpressionId(condition.ExpressionId);

                    if (expressionRow != null && !String.IsNullOrEmpty(expressionRow.ExpressionXml))
                    {
                        ValidationResult result = ValidateExpression(expressionRow.ApplicationId.ToString() + "-" + expressionRow.Category + "-" + expressionRow.ExpressionId.ToString(), expressionRow.ExpressionXml, promotionContext);
                        if (!result.IsValid)
                        {
                            includeSegment = false;
                            continue;
                        }
                        else
                        {
                            includeSegment = true;
                            break;
                        }
                    }
                }

                if (!includeSegment)
                {
                    continue;
                }

                segments.Add(segmentRow.SegmentId);
            }

            return(segments);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Evaluates the promotions.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="promotions">The promotions.</param>
        /// <param name="filter">The filter.</param>
        /// <returns>Collection of promotions that were applied. Look inside PromotionContext for actual rewards and for items
        /// that have been affected by these promotions.</returns>
        public PromotionItemCollection EvaluatePromotions(PromotionContext context, PromotionItemCollection promotions, PromotionFilter filter)
        {
            // Start checking discounts
            List <int> rowIndexes = new List <int>();

            // Retrieve all the coupons customer entered
            List <string> coupons = context.Coupons;

            // Retrieve customer segments, it should be initialized beforehand
            List <int> segments = context.Segments;

            // Retrieve customer id, it should be initialized beforehand
            Guid customerId = context.CustomerId;

            foreach (PromotionItem item in promotions)
            {
                // Set currently executed promotion
                context.CurrentPromotion = item;

                // If discount is global and other discount has been applied already, skip it
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel) && rowIndexes.Count != 0)
                {
                    continue;
                }

                // Check if it belongs to a group specified
                if (!String.IsNullOrEmpty(context.TargetGroup) && !context.TargetGroup.Equals(item.DataRow.PromotionGroup, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                // Check group exclusivity
                if (context.ExclusiveGroups.Contains(item.DataRow.PromotionGroup))
                {
                    continue;
                }

                // Check limits here
                int currentOrderPromotionCount = context.PromotionResult.GetCount(item.DataRow.PromotionId);

                // Start with per order limit
                if (item.DataRow.PerOrderLimit > 0 && currentOrderPromotionCount >= item.DataRow.PerOrderLimit)
                {
                    continue;
                }

                // Check application limit limit, only check when limit is set
                if (item.DataRow.ApplicationLimit > 0 && item.TotalUsedCount - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.ApplicationLimit)
                {
                    continue;
                }

                // Check customer limit, only check when limit is set and customer id is set
                if ((item.DataRow.CustomerLimit > 0 && customerId == Guid.Empty) || item.DataRow.CustomerLimit > 0 && item.GetCustomerUsageCount(customerId) - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.CustomerLimit)
                {
                    continue;
                }

                // First do simply checks that will take little time and save us from wasting processor time
                // -----------------------------------------------------------------------------------------
                if (!filter.IncludeInactive)
                {
                    // Skip if start date is past now
                    if (!item.Campaign.IsActive)
                    {
                        continue;
                    }

                    if (item.Campaign.StartDate > FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if end date is in the past
                    if (item.Campaign.EndDate < FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if start date is past now
                    if (item.DataRow.StartDate > FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if end date is in the past
                    if (item.DataRow.EndDate < FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Check promotion status
                    if (!item.DataRow.Status.Equals(PromotionStatus.Active))
                    {
                        continue;
                    }
                }

                if (!filter.IncludeCoupons)
                {
                    // Check coupons
                    string couponCode = item.DataRow.CouponCode;
                    if (!String.IsNullOrEmpty(couponCode))
                    {
                        if (coupons == null)
                        {
                            continue;
                        }

                        bool foundCoupon = false;
                        foreach (string coupon in coupons)
                        {
                            if (couponCode.Equals(coupon, StringComparison.OrdinalIgnoreCase))
                            {
                                foundCoupon = true;
                            }
                        }

                        if (!foundCoupon)
                        {
                            continue;
                        }
                    }
                }

                // Check catalog / node / entry filtering
                if (context.TargetEntriesSet.Entries.Count > 0)
                {
                    bool isValid = true;
                    foreach (PromotionEntry entry in context.TargetEntriesSet.Entries)
                    {
                        string catalogEntryId = entry.CatalogEntryCode;
                        string catalogNodeId  = entry.CatalogNodeCode;
                        string catalogName    = entry.CatalogName;

                        if (!String.IsNullOrEmpty(catalogEntryId) || !String.IsNullOrEmpty(catalogNodeId) || !String.IsNullOrEmpty(catalogName))
                        {
                            PromotionDto.PromotionConditionRow[] conditions = item.DataRow.GetPromotionConditionRows();
                            if (conditions != null && conditions.Length > 0)
                            {
                                foreach (PromotionDto.PromotionConditionRow condition in conditions)
                                {
                                    if (!String.IsNullOrEmpty(catalogEntryId) && !condition.IsCatalogEntryIdNull() && !condition.CatalogEntryId.Equals(catalogEntryId))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                    else if (!String.IsNullOrEmpty(catalogNodeId) && !condition.IsCatalogNodeIdNull() && !condition.CatalogNodeId.Equals(catalogNodeId))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                    else if (!String.IsNullOrEmpty(catalogName) && !condition.IsCatalogNameNull() && !condition.CatalogName.Equals(catalogName))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                }

                                if (!isValid)
                                {
                                    continue;
                                }
                            }
                        }
                    }
                    if (!isValid)
                    {
                        continue;
                    }
                }


                // Start doing more expensive checks here
                // -----------------------------------------------------------------------------------------
                if (!filter.IgnoreSegments)
                {
                    // Check customer segments, customer should belong to a segment for promotion to apply
                    CampaignDto.CampaignSegmentRow[] segmentRows = item.Campaign.GetCampaignSegmentRows();

                    // if there are no segments defined assume it applies to everyone
                    if (segmentRows != null && segmentRows.Length > 0)
                    {
                        // customer is not within any segment, so promotion does not apply
                        if (segments == null || segments.Count == 0)
                        {
                            continue;
                        }

                        // start checking segments
                        bool apply = false;
                        foreach (CampaignDto.CampaignSegmentRow row in segmentRows)
                        {
                            if (segments.Contains(row.SegmentId))
                            {
                                // mark promotion as apply and leave loop
                                apply = true;
                                break;
                            }
                        }

                        // if does not apply continue with a next promotion
                        if (!apply)
                        {
                            continue;
                        }
                    }
                }

                if (!filter.IgnoreConditions)
                {
                    // Validate expressions
                    if (item.Expressions.Count > 0)
                    {
                        bool isValid = true;
                        foreach (ExpressionDto.ExpressionRow expression in item.Expressions)
                        {
                            if (!String.IsNullOrEmpty(expression.ExpressionXml))
                            {
                                ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context);
                                if (!result.IsValid)
                                {
                                    isValid = false;
                                    break;
                                }
                            }
                        }

                        if (!isValid)
                        {
                            continue;
                        }
                    }
                }
                else
                {
                    // Create Award manually based on default settings
                    PromotionReward     reward = new PromotionReward(PromotionRewardType.EachAffectedEntry, item.DataRow.OfferAmount, item.DataRow.OfferType == 0 ? PromotionRewardAmountType.Percentage : PromotionRewardAmountType.Value);
                    PromotionItemRecord record = new PromotionItemRecord(context.TargetEntriesSet, context.TargetEntriesSet, reward);
                    record.PromotionItem = context.CurrentPromotion;
                    context.PromotionResult.PromotionRecords.Add(record);
                }

                if (!filter.IgnorePolicy)
                {
                    // Validate store policies
                    if (item.PolicyExpressions.Count > 0)
                    {
                        bool isValid = true;
                        foreach (ExpressionDto.ExpressionRow expression in item.PolicyExpressions)
                        {
                            if (!String.IsNullOrEmpty(expression.ExpressionXml))
                            {
                                ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context);
                                if (!result.IsValid)
                                {
                                    isValid = false;
                                    break;
                                }
                            }
                        }

                        if (!isValid)
                        {
                            // Invalidates all records added during this evaluation sequence
                            context.RejectRecords();
                            continue;
                        }
                    }
                }

                // Commits all records added during this evaluation sequence
                context.CommitRecords();

                // Apply item
                rowIndexes.Add(item.RowIndex);

                // Add item to a group if it is applied
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GroupLevel))
                {
                    context.ExclusiveGroups.Add(item.DataRow.PromotionGroup);
                }

                // Finish processing if global level item has been added
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel))
                {
                    break;
                }
            }

            // Assign curren promotion to null
            context.CurrentPromotion = null;

            return(new PromotionItemCollection(promotions, rowIndexes.ToArray()));
        }