A custom coupon code provider

Imagine you have a huge mailing campaign with personalized coupon codes for each customer. You would have a hard time validating those coupon codes, as a promotion can hold only one coupon code.

There is a way to do that though, with a custom coupon filter.

First I created a base class to use for the coupon providers, which take care of the coupon code validation. It implements an interface, which also will be used for registering the provider.  It contains a property for the type of the promotion it will be used for and a method that returns the coupon code.

public abstract class RemoteCouponProviderBase : IRemoteCouponProvider
where T : PromotionData
{
    public Type ProviderFor
    {
        get
        {
            return typeof(T);
        }
    }
    public abstract string GetCouponCode();
}

An implementation of the provider would look something like this, in this example I just return a code, but in the use case described above, you would probably connect to an external system to validate the code.

[ServiceConfiguration(typeof(IRemoteCouponProvider), Lifecycle = ServiceInstanceScope.Singleton)]
public class BuyFromCategoryGetItemDiscountRemoteCouponProvider : RemoteCouponProviderBase
{
    public override string GetCouponCode()
    {
        return "RemoteCoupon";
    }
}

In the coupon filter commerce loops through all promotion data in the context and checks for a coupon code. So basically you only need to replace that check.

To get the coupon provider for the promotion, if there is one, I get the original type of the promotion and check if there is an instance of IRemoteCouponProvider where the ProviderFor type matches the type of the promotion.

private static IRemoteCouponProvider GetRemoteCouponCodeProviderForPromotion(PromotionData promotionData)
{
    Type promotionType = promotionData.GetOriginalType();

    IRemoteCouponProvider provider = ServiceLocator.Current.GetAllInstances<IRemoteCouponProvider>().SingleOrDefault(p => p.ProviderFor == promotionType);

    return provider;
}

If there is a coupon provider, I use GetCouponCode on the provider and use the returned value, else use the coupon code from the promotion, if there has been entered a code of course.

IRemoteCouponProvider remoteCouponProvider = GetRemoteCouponCodeProviderForPromotion(promotionData: includedPromotion);

string code = remoteCouponProvider == null
                                  ? includedPromotion?.Coupon?.Code ?? string.Empty
: remoteCouponProvider.GetCouponCode();

All that is left now is to override the default implementation of the CouponFilter

services.AddSingleton<ICouponFilter, CustomCouponFilter>();

Although you can attach a coupon provider to all promotions, it’s probably best to create a custom promotion. That way you can hide e.g. the coupon code for the editors.

[ScaffoldColumn(false)]
public override CouponData Coupon { get; set; }

And maybe set a value for the coupon code, because with some promotions the items it applies to may show it as on sale, depending on your implementation of course, if there is no coupon code set.

public override void SetDefaultValues(ContentType contentType)
{
    base.SetDefaultValues(contentType);
    this.Coupon.Code = "32e65414d2224efe8ab36a54fb357853";
}

The complete example is in a Gist.

4 thoughts on “A custom coupon code provider

Leave a comment