Visitor group based campaign / promotions [Commerce v. 10.2.3 / CMS v. 10.3.2]

Member since: 2016
 

Hi

I am currently implementing visitor group based campaigns / promotions on our site, but have gotten some odd results from the promotionEngine.

I have a campaign, which is limited to a single visitor group, this campaign has a single entry promotion (BuyQuantityGetItemDiscount). 

Calling the 
_promotionEngine.GetDiscountPrices( new List<ContentReference> { variation.ContentLink }, currentMarket, currentMarket.DefaultCurrency, _referenceConverter, _lineItemCalculator);
yields no results.

But calling the 
_promotionEngine.Evaluate(variation.ContentLink, currentMarket, currentMarket.DefaultCurrency, RequestFulfillmentStatus.Fulfilled)
yields the wanted rewardDescription.

When placing the item in a cart (thus calling the cart.ApplyDiscounts(_promotionEngine, new PromotionEngineSettings()); ) the unit price is correctly calculated if and when being in the correct visitor group, but since I need to show the correct (discounted) price for the current user (based on the users visitor group), i need to get the users discounted price for the variation.

/Swensson 

#179150 Jun 01, 2017 11:05
  • Member since: 2012
     

    You can always use the _promotionEngine.Evaluate call and calculate the discount from the RewardDescription.SavedAmount yourself.

    The correct discounted price should be the price minus the saved amount, no?

    var discountedPrice = price - _promotionEngine.Evaluate().Sum(r=>r.SavedAmount);
    #179169 Jun 01, 2017 17:22
  • Member since: 2016
     

    Hi Erik

    That seems to work, but this leads me to a new question. 

    Is there any way to get the discounted price for a variation for a specific visitor group, without actually being in the group? 

    To elaborate, we have a scheduled job that replicates our products to ElasticSearch (for searching). In this scheduled job i need to get a specific visitor groups price, as well as the normal price. 

    #179176 Jun 02, 2017 9:22
  • Member since: 2012
     

    I'm sorry Mads, I have nothing but bad news for You.

    We have run into the exact same issue, the promotionengine always uses HttpContext.Current when evaluating.

    We have a ticket registered with Episerver developer support and they have made a bug for it #COM-4431.

    However it is still not visible in the bug list: http://world.episerver.com/support/Bug-list/

    So the status is unknown, We do not know when a solution will be forthcoming.

    #179192 Jun 02, 2017 14:02
  • Member since: 2016
     

    Bad news indeed, I have marked your previous answer since it answered the original question! :)

    Thanks for your time!

    #179193 Jun 02, 2017 14:09
  • Member since: 2016
     

    Erik Norberg

    We have a ticket registered with Episerver developer support and they have made a bug for it #COM-4431.
    However it is still not visible in the bug list: http://world.episerver.com/support/Bug-list/
    So the status is unknown, We do not know when a solution will be forthcoming.

    Good to hear! I created a feature request for something similar but got no response.

    A way to pass in a contactId or visitor group to the promotion engine would be awesome.

    My request:

    http://world.episerver.com/forum/developer-forum/Feature-requests/Thread-Container/2017/5/commerce-enable-promotion-system-to-look-at-purchaseorder-data-when-applying-discounts/

    #179208 Edited, Jun 04, 2017 11:44
  • Member since: 2016
     

    Hi Erik and Jafet

    I have just recieved this from Episerver Developer support today: 

    In case you need a workaround for your issue, you can create a custom promotion filter of your own.
    Please follow these steps as below:

    1. Create a class CustomCampaignVisitorGroupFilter inherited from CampaignVisitorGroupFilter (reference to the attach file CustomCampaignVisitorGroupFilter.cs)
    2. Add this line to the method ConfigureContainer in the SiteInitialization class: 
      services.AddTransient<CampaignVisitorGroupFilter, CustomCampaignVisitorGroupFilter>();


    and done, then you can get the discounted price by the method as below:

    GetDiscountedPrice(price, promotionEngine, visitorGroupName)
    {
      CustomCampaignVisitorGroupFilter.CurrentVisitorGroupName = visitorGroupName;
      var discountedPrice = price - promotionEngine.Evaluate().Sum(r=>r.SavedAmount);
      return discountedPrice;
    }



    using EPiServer.Commerce.Marketing;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using EPiServer.Personalization.VisitorGroups;
    using EPiServer.ServiceLocation;
    using EPiServer.Core;
    
    namespace EPiServer.Reference.Commerce.Site.CustomPromotionFilter
    {
    	public class CustomCampaignVisitorGroupFilter : CampaignVisitorGroupFilter
    	{
    		public static string CurrentVisitorGroupName;
    		private readonly IContentLoader _contentLoader;
    		private readonly IVisitorGroupRepository _visitorGroupRepository;
    
    		public CustomCampaignVisitorGroupFilter(ServiceAccessor<HttpContextBase> httpContextAccessor, IVisitorGroupRepository visitorGroupRepository, IVisitorGroupRoleRepository visitorGroupRoleRepository, IContentLoader contentLoader) : base(httpContextAccessor, visitorGroupRepository, visitorGroupRoleRepository, contentLoader)
    		{
    			_contentLoader = contentLoader;
    			_visitorGroupRepository = visitorGroupRepository;
    		}
    
    		public override PromotionFilterContext Filter(PromotionFilterContext filterContext)
    		{
    			var shouldFilterCampaign = new Dictionary<ContentReference, bool>();
    			var cachedVisitorGroupLookup = new Dictionary<Guid, bool>();
    
    			foreach (var promotion in filterContext.IncludedPromotions)
    			{
    				var campaignLink = promotion.ParentLink.ToReferenceWithoutVersion();
    				bool shouldFilter;
    				if (!shouldFilterCampaign.TryGetValue(campaignLink, out shouldFilter))
    				{
    					shouldFilter = ShouldFilter(campaignLink, cachedVisitorGroupLookup, filterContext);
    					shouldFilterCampaign[campaignLink] = shouldFilter;
    				}
    
    				if (!shouldFilter)
    				{
    					continue;
    				}
    
    				filterContext.ExcludePromotion(
    					promotion,
    					FulfillmentStatus.VisitorGroupRequired,
    					filterContext.RequestedStatuses.HasFlag(RequestFulfillmentStatus.NotFulfilled));
    			}
    
    			return filterContext;
    		}
    
    		private bool ShouldFilter(ContentReference campaignLink, IDictionary<Guid, bool> cachedVisitorGroupLookup, PromotionFilterContext filterContext)
    		{
    			SalesCampaign campaign;
    			if (!_contentLoader.TryGet(campaignLink, out campaign))
    			{
    				return true;
    			}
    
    			if (campaign.VisitorGroups == null || !campaign.VisitorGroups.Any())
    			{
    				return false;
    			}
    
    			foreach (var guid in campaign.VisitorGroups)
    			{
    				bool isValidate;
    				if (!cachedVisitorGroupLookup.TryGetValue(guid, out isValidate))
    				{
    					var visitorGroup = _visitorGroupRepository.Load(guid);
    					if (CurrentVisitorGroupName == null)
    					{
    						isValidate = true;
    					}
    					else
    					{
    						isValidate = String.Equals(visitorGroup.Name, CurrentVisitorGroupName, StringComparison.OrdinalIgnoreCase);
    					}						
    					cachedVisitorGroupLookup[guid] = isValidate;
    				}
    
    				if (isValidate)
    				{
    					filterContext.AddVisitorGroup(campaignLink, guid);
    					return false;
    				}
    			}
    
    			return true;
    		}
    	}
    }

    I havent tried this out yet, but wanted to share it with you guys!

    /Swensson

    #179584 Jun 15, 2017 15:22
  • Member since: 2012
     

    I am not entirely sure but I automatically repel at the sight of them setting a static property for the current visitor group name, it makes me suspect the risk of some really hairy threading issues.

    Getting customer specific prices would mean a lot of calls to evaluate with different values of the visitor group...

    If you only have the one visitor group I guess you can get it to work thou.

    #179585 Jun 15, 2017 15:44