/// <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)); }
/// <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)); }
/// <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); }
/// <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())); }