Virtual Happy Hour this month, Jun 28, we'll be getting a sneak preview at our soon to launch SaaS CMS!

Try our conversational search powered by Generative AI!

How to handle already discounted items with Commerce Promotions?



We run an episerver commerce (10.0.2) site where products for sale are imported from a different sales system.

The sales system can have promotions on products, and in these cases we get 2 prices for the product in the catalog,
discounted price and normal price.

So when we run additional promotions in commerce, we don't want the promotion engine to base the discount value on the already discounted price.

But at the same time we want the customer to always get the lowest result of either

- the normal price after it has been discounted by the episerver promotion, or
- the already discounted price without additional promotions from episerver.

So basically, we want the system to use the already discounted price for all situations except when applying promotions from commerce,  
and even when running promotions it still needs to be aware of the already discounted price, to determine which final price is the lowest.

We have considered the approach of overriding getdefaultprice, but this affects the pricing also when not running promotions (if I understand it correctly).

We also considered the approach of using a custom filter to filter out items that have discount prices, but this also seems unsuitable since we should not
filter them out if the result of the discount is lower than the already discounted price.

Is there a way to meet this requirement already present in commerce, or do you have any suggestions for an approach to meet it otherwise?

Best regards,


Feb 07, 2018 10:36

Out of my head, this might work (I haven't tried it, so you will have to try and validate yourself)

  • Store the pre-discounted prices with a special code, so it'll not available on GetDefaultPrice
  • Override/implement your own IPromotionEngine, so before applying the discounts, you check if the discounted price is better than the pre-discounted price, if yes, return it, if it is not, return the predefined price. You might create a promotion with 0% discount, just to be an information holder.

This is of course a very high level of the solution and it might or might not work, but it might give you a direction. 

Feb 07, 2018 13:27

Thanks for the reply Quan! I didn't expect a response from the Tower itself! :) 

From what you say I gather that there is no built-in way to handle this situation already and that was basically what I wanted to double-check before we make further plans. 

At a high level it's kinda simple - promotions should not give an additional discount for an already discounted price. 

However, this soon leads to complexities, with for example when different promotions should trigger at all, how to present the discounts on invoices and so on.

To solve this properly I imagine that the system as a whole would have to be aware of "original price" and "discounted price" in general, even when those originate from another system.

I realise we can probably implement this ourselves if we go deep enough - but it seems we'd have to consider not only the promotion engine but also related classes, and suddenly it gets a bit hairy. :) 

Anyway - now we at least know we aren't overlooking a simple option, so thanks again!

Best regards,


Feb 14, 2018 17:37

I try to answer the questions as much as I can :). I wish I had time to try a (quick and dirty) solution - but you probably have to try it yourself. If you succeed, please make sure to share it in a blog post. Your back up plan is expert services from Episerver :) 

Edited, Feb 15, 2018 10:05


We have a similar setup that we are struggling with. Did you solve this?



Apr 25, 2018 14:54


Partially - what we ended up doing was to upgrade commerce to a version over 10.1 in order to get access to entryfilters, and made a filter that excludes any discounted items from promotions altogether. 

I followed these instructions for making the filter:

This is a bit heavy-handed, somewhat confusing to the customer in certain cases, and doesn't solve all the requirements of my initial question of course. But it seems to work reliably and it solves the biggest issue for the client (items being sold far too cheaply if they get double-discounts).

Maybe a more advanced way to handle scenarios like ours can get added to Episerver in the future? :) 



Apr 25, 2018 15:35

Yes, possibly. That was the reason I asked you to write a blog post. We need to understand the problem, the impact, so we can decide on the solution and the priority :) 

Apr 25, 2018 15:38

Our scenario is like this on a basic level. We have B2B customers that have fixed discounts. They might for example have 10% off everything and then 20% just one category. These are the approaches we have tried so far and where we have failed. Ill write the full scenarios to see if we have missed something. If so please correct me with a solutions so that we can try it out 😊

Solution: Create visitor groups for each customer and add the promotions accordingly.

Problem: Say for example that there is a special sale on one item with 50% discount, then how do we solve this? Even if we order them correctly (highest 50% discount first) and say that they cannot be combined then we will hit the 50% but all the other items in the basket will not get a discount. If we say they can be combined, then there will be a 20 % discount on some items and a almost 70% discount on the sale item. And this only includes 20% based promotions. If we where to throw in a couple of buy 2 get 1 free we are pretty screwed.

Solution: Create special “price lists” for each customer with the lower price

Problem: This is pretty much the same as the original post with the difference that we don’t have any backing pricing system. And since there are no way to lower the price of every item in a category with X% automatically we would have to write/buy a separate system for just that. And that would still leave us in the same position as the original post.


First off it would be nice with some kind of setting on the promotion engine to return the “best price for current basket”. Going through all combination of promotions and not just the order.

Second it would be good with some way to make promotions only semi excluding. For example if we have a promotion that is 10% off everything and a 20% shirts we should be able to get a 20% off all shirts but still get 10% everything else in the basket.



Apr 25, 2018 16:05

We reported that to episerver a long time ago and they have provided a feature for it:

_promotionEngine.Run(cart, new PromotionEngineSettings { ExclusionLevel = ExclusionLevel.Unit})
Apr 26, 2018 11:37

Ok that might work in our favor. How do you use that when for example calling GetDiscountPrices? GetDiscountPrices does not take promotionEngineSettings in the method call. And since it is an extension to the interface IPromotionEngine its impossible to override with your own implementation.

Apr 26, 2018 11:53

We don't call the extension methods, just Run and Evaluate on the promotion engine directly. Evaluate doesn't have the settings either but we just use that to list which promotions are available for entries. Whenever we want a price we use Run.

The extension methods all uses those two functions internally and if you want a custom implementation you just ignore the extensions.

Apr 26, 2018 12:13

The problem is that some of the internal code uses those extensions... I guess that if we override the run method with ExclusionLevel = ExclusionLevel.Unit and accept that limitation then that will hopefully propagate to the other functionality aswell. 

Apr 26, 2018 13:01

The extensionmethods pass an empty settings object to PromotionEngine.Run(IOrderGroup, PromotionEngineSettings).

So creating your own promotion engine and registering that for IPromotionEngine in your IoC should do the trick.

Code for your promotion engine would look something like this:

    public class MyPromotionEngine : PromotionEngine
        public MyPromotionEngine(PromotionEngineContentLoader promotionEngineContentLoader, IRedemptionLimitService redemptionLimitService, PromotionFilters promotionFilters, PromotionApplicator promotionExecutor, ILineItemCalculator lineItemCalculator, IShippingCalculator shippingCalculator, IOrderFormCalculator orderFormCalculator, IEntryFilter entryFilter) : base(promotionEngineContentLoader, redemptionLimitService, promotionFilters, promotionExecutor, lineItemCalculator, shippingCalculator, orderFormCalculator, entryFilter)

        public override IEnumerable<RewardDescription> Run(IOrderGroup orderGroup, PromotionEngineSettings settings)
            settings.ExclusionLevel = ExclusionLevel.Unit;
            return base.Run(orderGroup, settings);
Apr 26, 2018 16:27
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.