Creating tiered pricing for organizations and visitor groups
This is the third part in a 3-part series about understanding and extending the EPiCommerce tiered pricing engine. This is a demonstration of how you'd extend tiered pricing to organization-specific and visitor-group-specific pricing. The first and second parts can be found here:
Part 1: Intro to Tiered Pricing
Part 2: How to extend Tiered Pricing
Organization-specific pricing
To add pricing specific to organizations, follow these steps:
1. Add a new sale type in the ecf.catalog.config file, the SalePriceTypes section:
<add key="CustomPricing.Organization" value="3" description="Organization"></add>
The key is the Session variable name. There is no required convention in the name except that it of course be unique. The value must be a number, consecutive to the other tiered pricing types. The description is the name that will be displayed in Commerce Manager as a new sale type option.
Once you’ve saved this change, when you edit/add tiered pricing, you'll see a new option for Organization in the Sale Type dropdown and be able to add tiered pricing for an organization. If you specify an organization name for the sale code, you have now set a tiered price for customers associated with that organization.
2. Add code somewhere in your front end site to set the session variable like this:
//map the customer organization to a session variable for pricing mapping
if (Session["CustomPricing.Organization"] == null &&
CustomerContext.Current.CurrentContact != null &&
CustomerContext.Current.CurrentContact.ContactOrganization != null)
{
string orgName =
CustomerContext.Current.CurrentContact.ContactOrganization.Name;
Session["CustomPricing.Organization"] = orgName;
}
You may want to add code so that, when a user logs out, the session variable is set to null. Now, if you set a tiered price for an organization for a particular SKU (and its the lowest possible price for the user), it will be the displayed price for that SKU for users associated with that organization when they authenticate to the site. An obvious pre-requisite is you’ll need to have organizations created in the customer subsystem in Commerce Manager and users associated with them to use this tiered pricing.
3. If you want to display a dropdown with a list of organizations when you are adding the tiered price for an organization in Commerce Manager, there's one more step. You need to create a control that you register with the system.
a. Create a new empty web project.
b. Add a new web control that implements the IAdminTabControl and IAdminContextControl interfaces. See the example implementation below.
The IAdminContextControl interface has one method, LoadContext(), which is called by Commerce Manager to provide the sale code to display what value has already been saved, if any.
The IAdminTabControl interface has one method, SaveChanges(), which is called by Commerce Manager to allow the sale code to be updated to the new value specified by the user or other business logic.
c. You'll need to add references to the project. At a minimum, you'll need to add references to the EPiServer.dll and Mediachase.Commerce.dll.
d. Copy the project dll for the new web project into the commerce manager project bin folder.
e. Copy the web control ascx file into the Apps/Catalog/Modules folder of the Shared folders for your site.
f. In the ecf.catalog.config, amend the new key from step 1 above with something like :
controlUrl="~/Apps/Catalog/Modules/OrganizationPicker.ascx" to map to the new control’s name and location.
Now you can set tiered pricing for organizations and the organizations are conveniently populated in a dropdown list.
VisitorGroup
This is a little different from the organization list. The reason is that a user can be associated with multiple visitor groups and the pricing engine maps one session variable as one tiered pricing target. So this implementation is designed to create a single sale type for each visitor group that you're providing pricing for. Here are the steps to add tiered pricing for a visitor group:
1. Add a new sale type in the ecf.catalog.config file like this:
<add key="CustomPricing.VisitorGroup.special" value="4"
description="Visitor Group - Special"
controlUrl="~/Apps/Catalog/Modules/VisitorGroupControl.ascx"></add>
where “special” is the name of the visitor group we're targeting. The key and value again must be unique. The controlUrl points to another attached file below.
2. Add code somewhere in your application to set the VisitorGroup session variable. It should execute with every page load as a user’s membership to a VisitorGroup can change during a session. The code could be written to go through the catalog config file and add all specified visitor group price types, in which case it could look something like this:
string visitorGroup;
string visitorGroupPrefix = "CustomPricing.VisitorGroup.";
string visitorGroupSessionVariable;
EPiServer.Personalization.VisitorGroups.VisitorGroupHelper hlpr = null;
//go through the sale price types from the ecf.catalog.config file
Mediachase.Commerce.Catalog.SalePriceTypeCollection salesPriceTypes =
CatalogConfiguration.Instance.SalePriceTypes;
foreach (SalePriceTypeDefinition saleType in salesPriceTypes)
{
//if any sale types have a prefix of the custom pricing namespace
if (saleType.Key.StartsWith(visitorGroupPrefix))
{
visitorGroupSessionVariable = saleType.Key;
if (hlpr == null)
hlpr = new VisitorGroupHelper();
visitorGroup = saleType.Key.Replace(visitorGroupPrefix, "");
//if the user is in the visitor group, add a session
//variable for pricing mapping
if (hlpr.IsPrincipalInGroup(PrincipalInfo.CurrentPrincipal,
visitorGroup))
{
Session[visitorGroupSessionVariable] = "true";
}
else
Session.Remove(visitorGroupSessionVariable);
}
}
In this case, the Sale Code is being set to "true", an arbitrary value to map to the value set in the control in step 3.
3. Add a control the same way as outlined above for the organization tiered pricing control. See below for the demo control. The sale code is set to “true” always, since there’s no other specific information needed to map a visitor group to a tiered price.
There you go. You should now also be able to add tiered pricing for a visitor group. These are just a few examples of what you can do to expand the scope of tiered pricing. I'm sure there are others with even better ways to implement this, particularly with the VisitorGroup classes - please share and I'll update the code with improvements. By the way, I have to credit the idea for the visitor group tiered pricing to a brainstorm with Chris Pope, Andreas Sjernstrom, and Sofia Max - thanks!
On a final note, the pricing engine is getting updated with a provider model in the next version of EPiCommerce, making it easier to implement your custom pricing logic in EPiCommerce. I'll be blogging about that shortly after that is released.
Download the code mentioned above here.
Shannon, it's a great description of custom tier pricing, but I cannot make it work. When I add new lines to config, I start seeing them in Sale Type dropdown - and that's ok.
But when I choose any of my custom Sale Types, and trying to save product - I see exception from Commerce:
The MERGE statement conflicted with the FOREIGN KEY constraint "FK_PriceGroup_PriceType". The conflict occurred in database "database", table "dbo.PriceType", column 'PriceTypeId'.
From what I see, items from SalePriceTypes config section were not added to PriceType table in database, so Sale Prices for product could not be saved.
My question is - is it supposed to work in such manner, and I need manually insert these Sale Types in config AND database? Or, as you never mentioned this step, it's something misconfigured in Commerce?
Hey Shannon-
Can you update this post to indicate what has changed in the new Provider model as much of the above 3 posts no longer apply.