Below are two classes that can be added to any Sitecore commerce plugin that will enable promotions that are applied based on the tags or templates assigned to the product.

The tagging example provides a very flexible way of applying a promotion.

These two classes enable the following two business scenarios :-

  1. I would like to apply a promotion to all products and or product variants that have the following tag applied…
  2. I would like to apply a promotion to all products that implement a specific Sitecore item template…

Both examples set the price to X dollars i.e. a set amount but the code can easily be modified to enable percentage or set amount off the existing price.

To enable to functionality follow these steps :-

  1. Create new classes named based on the example code in your new plugin or one of the existing sample plugins such as “Sitecore.Commerce.Plugin.AdventureWorks”.
  2. Copy the code below over the new classes.

Your project should look something like this…

tag pricing 1.png

The new functionality will automatically become available in the promotions user interface as they implement the correct interfaces.

Go to the pricing and promotions manager and create a new promotion, you should see the new options in the benefits drop down list.

Note : You will need to apply the tags to the variant not the product if you are using variants.

A promotion that enabled the business scenario outlined above should look like this…

tag pricing 2.png

The tag example…


namespace Plugin.Pricing.Action
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.Plugin.Carts;
using Sitecore.Commerce.Plugin.Pricing;
using Sitecore.Framework.Rules;
[EntityIdentifier("All items with a specific tag set price")]
public class CartAllItemsWithTagSpecifyAmountAction : ICartLineAction
{
public void Execute(IRuleExecutionContext context)
{
var commerceContext = context.Fact<CommerceContext>();
if (commerceContext == null)
{
return;
}
var cart = (commerceContext.Objects.OfType<Cart>()).FirstOrDefault();
var totals = (commerceContext.Objects.OfType<CartTotals>()).FirstOrDefault();
if ((cart != null) && cart.Lines.Any() && ((totals != null) && totals.Lines.Any()) == false)
{
return;
}
var source = new List<CartLineComponent>();
foreach (var cartLine in cart.Lines.Where(x => x.HasComponent<CartProductComponent>()))
{
var firstOrDefault = cartLine.GetComponent<CartProductComponent>().Tags.FirstOrDefault(t => t.Name == this.Tag.Yield(context));
if (!string.IsNullOrEmpty(firstOrDefault?.Name))
{
source.Add(cartLine);
}
}
if (!source.Any())
{
return;
}
var model = commerceContext.Objects.OfType<PropertiesModel>().FirstOrDefault();
if (model == null)
{
return;
}
foreach (var line in source)
{
if (!totals.Lines.ContainsKey(line.Id))
{
continue;
}
var discount = commerceContext.GetPolicy<KnownCartAdjustmentTypesPolicy>().Discount;
var d = this.Price.Yield(context);
if (commerceContext.GetPolicy<GlobalPricingPolicy>().ShouldRoundPriceCalc)
{
d = decimal.Round(d, commerceContext.GetPolicy<GlobalPricingPolicy>().RoundDigits, commerceContext.GetPolicy<GlobalPricingPolicy>().MidPointRoundUp ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven);
}
decimal amount;
var currentAmount = totals.Lines[line.Id].SubTotal.Amount;
if (currentAmount <= d)
{
amount = d currentAmount;
totals.Lines[line.Id].SubTotal.Amount += amount;
}
else
{
amount = currentAmount d;
amount = amount * decimal.MinusOne;
totals.Lines[line.Id].SubTotal.Amount += amount;
}
var item = new CartLineLevelAwardedAdjustment
{
Name = (string) model.GetPropertyValue("PromotionText"),
DisplayName = (string) model.GetPropertyValue("PromotionCartText"),
Adjustment = new Money(commerceContext.CurrentCurrency(), amount),
AdjustmentType = discount,
IsTaxable = false,
AwardingBlock = "CartAllItemsWithTagSpecifyAmountAction"
};
line.Adjustments.Add(item);
line.GetComponent<MessagesComponent>().AddMessage(commerceContext.GetPolicy<KnownMessageCodePolicy>().Promotions, $"PromotionApplied: {model.GetPropertyValue("PromotionId")}");
}
}
public IRuleValue<decimal> Price { get; set; }
public IRuleValue<string> Tag { get; set; }
}
}

The Item template (product definition)…


namespace Plugin.Pricing.Action
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.Plugin.Carts;
using Sitecore.Commerce.Plugin.Pricing;
using Sitecore.Framework.Rules;
[EntityIdentifier("All items with a specific item template set price")]
public class CartAllItemsWithTemplateSpecifyAmountAction : ICartLineAction
{
public void Execute(IRuleExecutionContext context)
{
var commerceContext = context.Fact<CommerceContext>();
if (commerceContext == null)
{
return;
}
var cart = (commerceContext.Objects.OfType<Cart>()).FirstOrDefault();
var totals = (commerceContext.Objects.OfType<CartTotals>()).FirstOrDefault();
if ((cart != null) && cart.Lines.Any() && ((totals != null) && totals.Lines.Any()) == false)
{
return;
}
// This the code that decides which lines to discount
var source = new List<CartLineComponent>();
foreach (var cartLine in cart.Lines.Where(x => x.HasComponent<CartProductComponent>()))
{
if(cartLine.GetComponent<CartProductComponent>().ItemTemplate == this.Template.Yield(context))
{
source.Add(cartLine);
}
}
if (!source.Any())
{
return;
}
var model = commerceContext.Objects.OfType<PropertiesModel>().FirstOrDefault();
if (model == null)
{
return;
}
foreach (var line in source)
{
if (!totals.Lines.ContainsKey(line.Id))
{
continue;
}
var discount = commerceContext.GetPolicy<KnownCartAdjustmentTypesPolicy>().Discount;
var d = this.Price.Yield(context);
if (commerceContext.GetPolicy<GlobalPricingPolicy>().ShouldRoundPriceCalc)
{
d = decimal.Round(d, commerceContext.GetPolicy<GlobalPricingPolicy>().RoundDigits, commerceContext.GetPolicy<GlobalPricingPolicy>().MidPointRoundUp ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven);
}
decimal amount;
var currentAmount = totals.Lines[line.Id].SubTotal.Amount;
if (currentAmount <= d)
{
amount = d currentAmount;
totals.Lines[line.Id].SubTotal.Amount += amount;
}
else
{
amount = currentAmount d;
amount = amount * decimal.MinusOne;
totals.Lines[line.Id].SubTotal.Amount += amount;
}
var item = new CartLineLevelAwardedAdjustment
{
Name = (string) model.GetPropertyValue("PromotionText"),
DisplayName = (string) model.GetPropertyValue("PromotionCartText"),
Adjustment = new Money(commerceContext.CurrentCurrency(), amount),
AdjustmentType = discount,
IsTaxable = false,
AwardingBlock = "CartAllItemsWithProductDefinitionSpecifyAmountAction"
};
line.Adjustments.Add(item);
line.GetComponent<MessagesComponent>().AddMessage(commerceContext.GetPolicy<KnownMessageCodePolicy>().Promotions, $"PromotionApplied: {model.GetPropertyValue("PromotionId")}");
}
}
public IRuleValue<decimal> Price { get; set; }
public IRuleValue<string> Template { get; set; }
}
}