Skip to content

Instantly share code, notes, and snippets.

@davidknipe
Last active June 17, 2021 07:24
Show Gist options
  • Select an option

  • Save davidknipe/3c69253730b0872e2b5a79d6723f2d8d to your computer and use it in GitHub Desktop.

Select an option

Save davidknipe/3c69253730b0872e2b5a79d6723f2d8d to your computer and use it in GitHub Desktop.
Custom promotion to allow unique coupon codes created in Episerver Campaign to be used in Episerver Commerce discounts
using System;
using System.Collections.Generic;
using System.Linq;
using Campaign.CouponServices.Interfaces;
using EPiServer.Commerce.Marketing;
using EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Discount;
using EPiServer.Security;
using Mediachase.Commerce.Security;
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.CouponFilter
{
/// <summary>
/// Used to filter out promotions that use Episerver Campaign to issue coupon codes
/// </summary>
public class CampaignCouponFilter : ICouponFilter
{
private readonly ICampaignCoupons _campaignCoupons;
public CampaignCouponFilter(ICampaignCoupons campaignCoupons)
{
_campaignCoupons = campaignCoupons;
}
public PromotionFilterContext Filter(PromotionFilterContext filterContext, IEnumerable<string> couponCodes)
{
var codes = couponCodes.ToList();
var userEmail = PrincipalInfo.CurrentPrincipal?.GetCustomerContact()?.Email;
foreach (var includedPromotion in filterContext.IncludedPromotions)
{
// Check if this is the right promotion type, if not ignore
var couponDrivenDiscount = includedPromotion as ICampaignCouponDiscount;
if (couponDrivenDiscount == null) continue;
// If we don't have any codes to check or the users email then unique
// coupon code promotion types are not valid so exclude them
if (!codes.Any() || string.IsNullOrEmpty(userEmail))
{
filterContext.ExcludePromotion(includedPromotion, FulfillmentStatus.CouponCodeRequired,
filterContext.RequestedStatuses.HasFlag(RequestFulfillmentStatus.NotFulfilled));
continue;
}
long couponBlockId;
if (long.TryParse(couponDrivenDiscount.CouponType, out couponBlockId))
{
foreach (var couponCode in codes)
{
// Check if the code its assigned to the user and that has not been used
if (_campaignCoupons.IsCouponAssigned(userEmail, couponBlockId, couponCode) &&
_campaignCoupons.IsCouponUsed(couponBlockId, couponCode) == false)
{
// The code hasn't been used and is assigned to the user so we can
// allow this to be connected to the promotion for this user
filterContext.AddCouponCode(includedPromotion.ContentGuid, couponCode);
}
else
{
// Exclude this promotion as its been used and/or it isn't assigned to the user
filterContext.ExcludePromotion(includedPromotion, FulfillmentStatus.CouponCodeRequired,
filterContext.RequestedStatuses.HasFlag(RequestFulfillmentStatus.NotFulfilled));
}
}
}
}
return filterContext;
}
protected virtual IEqualityComparer<string> GetCodeEqualityComparer()
{
return StringComparer.OrdinalIgnoreCase;
}
}
}
using System.Collections.Generic;
using Campaign.CouponServices.Interfaces;
using EPiServer.ServiceLocation;
using EPiServer.Shell.ObjectEditing;
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Discount
{
public class CouponCodeTypesSelectionFactory : ISelectionFactory
{
private readonly ICampaignCouponDefinition _campaignCouponDefinition;
public CouponCodeTypesSelectionFactory()
{
_campaignCouponDefinition = ServiceLocator.Current.GetInstance<ICampaignCouponDefinition>();
}
public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
var allCouponDefinitions = _campaignCouponDefinition.GetAllCouponDefinitions();
var couponItems = new List<ISelectItem>();
foreach (var couponDefinition in allCouponDefinitions)
{
couponItems.Add(new SelectItem()
{
Text = couponDefinition.CouponName + " (" + couponDefinition.CouponSource + ")",
Value = couponDefinition.CouponId
});
}
return couponItems;
}
}
}
using System.Collections.Generic;
using Campaign.CouponServices.Interfaces;
using EPiServer.Commerce.Marketing;
using EPiServer.Core;
using EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Discount;
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Reporting
{
public class CouponUsageImpl : ICouponUsage
{
private readonly ICampaignCoupons _campaignCoupons;
private readonly IContentRepository _contentRepository;
public CouponUsageImpl(IContentRepository contentRepository, ICampaignCoupons campaignCoupons)
{
_contentRepository = contentRepository;
_campaignCoupons = campaignCoupons;
}
public void Report(IEnumerable<PromotionInformation> appliedPromotions)
{
// This method allows us to report couple usage so we
// will look for all promotions with a coupon applied
foreach (var promotion in appliedPromotions)
{
var content = _contentRepository.Get<IContent>(promotion.PromotionGuid);
var promotionData = content as SpendAmountGetOrderDiscountWithCoupon;
long couponTypeId;
if (promotionData == null || long.TryParse(promotionData.CouponType, out couponTypeId) == false) return;
// Safe to mark the coupon as used
_campaignCoupons.MarkCouponAsUsed(couponTypeId, promotion.CouponCode);
}
}
}
}
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Discount
{
/// <summary>
/// Used to identify promotion types that use coupons issued by Episerver Campaign
/// </summary>
public interface ICampaignCouponDiscount
{
string CouponType { get; set; }
}
}
using EPiServer.Commerce.Marketing;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.CouponFilter;
using EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Reporting;
using EPiServer.ServiceLocation;
using EPiServer.ServiceLocation.Compatibility;
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Init
{
[InitializableModule]
[ModuleDependency(typeof(ServiceContainerInitialization))]
[ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
public class RegisterImplementations : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
// Coupon filter for discounts using unique coupon codes from Campaign
//context.Services.AddSingleton<ICouponFilter, CampaignCouponFilter>();
context.Services.Configure(
c =>
{
c.For<ICouponFilter>().Use<CampaignCouponFilter>();
});
context.Services.Configure(
c =>
{
c.For<ICouponUsage>().Use<CouponUsageImpl>();
});
}
public void Initialize(InitializationEngine context) { }
public void Uninitialize(InitializationEngine context) { }
}
}
using System.ComponentModel.DataAnnotations;
using EPiServer.Commerce.Marketing;
using EPiServer.Commerce.Marketing.DataAnnotations;
using EPiServer.Commerce.Marketing.Promotions;
using EPiServer.DataAnnotations;
using EPiServer.Shell.ObjectEditing;
namespace EPiServer.Reference.Commerce.Site.Features.CampaignCoupons.Discount
{
[ContentType(GUID = "F6B2B6EC-AA3F-415D-8802-C3FE18DA74A8"
, DisplayName = "Get a discount using a unique coupon code created by Episerver Campaign"
, Description = "Used to give discounts for individual coupon codes that have been sent to the user by Episerver Campaign")]
[AvailableContentTypes(Include = new[] {typeof(PromotionData)})]
[ImageUrl("~/Features/CampaignCoupons/campaign.png")]
public class SpendAmountGetOrderDiscountWithCoupon : SpendAmountGetOrderDiscount, ICampaignCouponDiscount
{
// Hide the default coupon code
[ScaffoldColumn(false)]
public override CouponData Coupon { get; set; }
[PromotionRegion(PromotionRegionName.Condition)]
[SelectOne(SelectionFactoryType = typeof(CouponCodeTypesSelectionFactory))]
[Display(
Order = 1,
Name = "Coupon of this type has been sent to the user")]
public virtual string CouponType { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment