A condition with customized logic can be created by implementing the IConditon and IUIExtension interfaces. This is similar to how a custom action is created. The only difference is that the ICondition interface is implemented instead of the IAction one. Apart from that, the same principles apply. Please refer to the article about custom action first, then implement the code presented here.
These are the four steps:
- Create a separate project
- Create a class in the project
- Create a web-user control
- Import condition strings
Create a separate project in your solution, where you can place your custom class.
Create a class in the project and implement the following two interfaces:
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.ICondition
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.IUIExtension
From Litium 7.2, two more conditions can be implemented for increased flexibility:
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.IConditionWithOrder
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.IRequireCampaignInfo
Example: Excluding articles from the order total
The default order-total condition calculates the order total on all products in the cart, but does not allow specific products to be excluded. This is not ideal in when large percentage discounts are given. For example, a 50% discount is given for a particular product called "A" (regular price 100 SEK) when the order total exceeds 90 SEK. If the normal order-total condition is used, the campaign will be applied when the user selects product A. This happens because the product list price is 100 SEK and the limit for the campaign order-total condition is 90 SEK. But once the campaign is applied, the order total will be 50 SEK because of the 50% discount.
To avoid the above scenario, we need to use an order-total condition that will exclude the product "A" when the order total is calculated.

Here is the complete source of the above class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Litium.Foundation.Modules.ECommerce;
using Litium.Foundation.Modules.ECommerce.Carriers;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.ConditionTypes;
using Litium.Foundation.Modules.ExtensionMethods;
using Litium.Foundation.Security;
namespace Litium.Studio.KC.Samples.Campaigns
{
/// <summary>
/// Order total condition
/// </summary>
public class OrderTotalExcludingArticlesCondition : CartConditionType
{
private const string PATH = "~/Site/ECommerce/Campaigns/KC/OrderTotalExcludingArticlesConditionControl.ascx";
Data m_data;
/// <summary>
/// Initializes the specified data.
/// </summary>
/// <param name="data">The data.</param>
protected override void Initialize(object data)
{
base.Initialize(data);
m_data = (Data)data;
}
/// <summary>
/// Gets the panel path.
/// </summary>
/// <value>The panel path.</value>
public override string PanelPath { get { return PATH; } }
/// <summary>
/// Gets a value indicating whether condition depends on order total.
/// If true, an order total calculation will be done before invoking the condition.
/// </summary>
/// <value>
/// <c>true</c> if condition depends on order total otherwise, <c>false</c>.
/// </value>
public override bool DependsOnOrderTotal
{
get
{
return true;
}
}
/// <summary>
/// Evaluates the specified condition.
/// </summary>
/// <param name="conditionArgs">The condition args.</param>
/// <returns></returns>
protected override IEnumerable<OrderCarrier> Evaluate(ConditionArgs conditionArgs)
{
decimal subTotal = 0;
switch (m_data.SelectedIdType)
{
case Data.SelectionCriteria.Variants:
subTotal = (m_data.IncludeVat) ?
conditionArgs.OrderRows.Where(x => !m_data.SelectedIDs.Contains(x.ArticleID)).Select(y => y.OrderRowCarrier.TotalPriceWithVAT).Sum() :
conditionArgs.OrderRows.Where(x => !m_data.SelectedIDs.Contains(x.ArticleID)).Select(y => y.OrderRowCarrier.TotalPrice).Sum();
break;
case Data.SelectionCriteria.Assortments:
subTotal = (m_data.IncludeVat) ?
conditionArgs.OrderRows.Where(x => !x.AssortmentIDs.Intersect(m_data.SelectedIDs).Any()).Select(y => y.OrderRowCarrier.TotalPriceWithVAT).Sum() :
conditionArgs.OrderRows.Where(x => !x.AssortmentIDs.Intersect(m_data.SelectedIDs).Any()).Select(y => y.OrderRowCarrier.TotalPrice).Sum();
break;
case Data.SelectionCriteria.Categories:
subTotal = (m_data.IncludeVat) ?
conditionArgs.OrderRows.Where(x => !x.CategorySystemIds.Intersect(m_data.SelectedIDs).Any()).Select(y => y.OrderRowCarrier.TotalPriceWithVAT).Sum() :
conditionArgs.OrderRows.Where(x => !x.CategorySystemIds.Intersect(m_data.SelectedIDs).Any()).Select(y => y.OrderRowCarrier.TotalPrice).Sum();
break;
case Data.SelectionCriteria.ProductLists:
subTotal = (m_data.IncludeVat) ?
conditionArgs.OrderRows.Where(x => !m_data.SelectedIDs.Intersect(x.ProductSetIDs).Any()).Select(y => y.OrderRowCarrier.TotalPriceWithVAT).Sum() :
conditionArgs.OrderRows.Where(x => !m_data.SelectedIDs.Intersect(x.ProductSetIDs).Any()).Select(y => y.OrderRowCarrier.TotalPrice).Sum();
break;
}
return (from order in conditionArgs.OrderCarriers
where
(m_data.ShouldBeEqualOrMore && (subTotal >= m_data.TotalPrice))
|| (!m_data.ShouldBeEqualOrMore && (subTotal <= m_data.TotalPrice))
select order);
}
/// <summary>
/// Condition data.
/// </summary>
[Serializable]
public class Data
{
/// <summary>
/// Gets or sets the total price.
/// </summary>
/// <value>The total price.</value>
public decimal TotalPrice { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [include vat].
/// </summary>
/// <value><c>true</c> if [include vat]; otherwise, <c>false</c>.</value>
public bool IncludeVat { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [should be more].
/// </summary>
/// <value><c>true</c> if [should be more]; otherwise, <c>false</c>.</value>
public bool ShouldBeEqualOrMore { get; set; }
/// <summary>
/// Define the type of Ids selected for the <see cref="Data.SelectedIDs"/> property.
/// </summary>
public enum SelectionCriteria
{
/// <summary>
/// Variant ids
/// </summary>
Variants,
/// <summary>
/// Category group íds
/// </summary>
Categories,
/// <summary>
/// Assortment ids.
/// </summary>
Assortments,
/// <summary>
/// Product list ids.
/// </summary>
ProductLists
}
/// <summary>
/// Gets or sets the selection criteria.
/// </summary>
/// <value>The selection criteria.</value>
public SelectionCriteria SelectedIdType { get; set; }
/// <summary>
/// Gets or sets list of selected Ids
/// </summary>
/// <value>The selected I ds.</value>
public List<Guid> SelectedIDs { get; set; }
}
/// <summary>
/// Gets the description.
/// </summary>
/// <param name="languageID">The language ID.</param>
/// <returns></returns>
public override string GetDescription(Guid languageID)
{
string description = string.Empty;
try
{
SecurityToken token = ModuleECommerce.Instance.AdminToken;
StringBuilder sb = new StringBuilder();
if (m_data != null)
{
string articleName = string.Empty;
if (m_data.IncludeVat)
{
var withVatDescription = ModuleECommerce.Instance.Strings.GetValue("OrderTotalConditionDescriptionWithVAT", languageID, true);
sb.AppendFormat(withVatDescription, m_data.ShouldBeEqualOrMore ? " >= " : " <= ", m_data.TotalPrice);
}
else
{
var withoutVatdescription = ModuleECommerce.Instance.Strings.GetValue("OrderTotalConditionDescriptionWithoutVAT", languageID, true);
sb.AppendFormat(withoutVatdescription, m_data.ShouldBeEqualOrMore ? " >= " : " <= ", m_data.TotalPrice);
}
sb.AppendLine();
switch (m_data.SelectedIdType)
{
case Data.SelectionCriteria.Variants:
sb.Append(ModuleECommerce.Instance.Strings.GetValue("OrderTotalExcludingArticlesConditionExcludeArticles", languageID, true));
foreach (var item in m_data.SelectedIDs.Select(x => x.GetVariant()))
{
if (item != null)
{
sb.Append(Environment.NewLine);
sb.Append(item.GetDisplayName(languageID));
}
}
break;
case Data.SelectionCriteria.Assortments:
sb.Append(ModuleECommerce.Instance.Strings.GetValue("OrderTotalExcludingArticlesConditionExcludeAssortment", languageID, true));
StringBuilder sbTemp = new StringBuilder();
foreach (var item in m_data.SelectedIDs.Select(x => x.GetAssortment()))
{
if (item != null)
{
sbTemp.Append(" ");
sbTemp.Append(item.GetDisplayName(languageID));
sbTemp.Append(",");
}
}
//remove last comma.
if (sbTemp.Length > 0)
{
sbTemp.Remove(sbTemp.Length - 1, 1);
}
sb.Append(string.Format(sb.ToString(), sbTemp));
break;
case Data.SelectionCriteria.Categories:
sb.Append(ModuleECommerce.Instance.Strings.GetValue("OrderTotalExcludingArticlesConditionExcludeProductGroup", languageID, true));
foreach (Guid item in m_data.SelectedIDs)
{
var category = item.GetCategory();
if (category != null)
{
sb.Append(Environment.NewLine);
sb.Append(category.GetDisplayName(languageID));
}
}
break;
case Data.SelectionCriteria.ProductLists:
sb.Append(ModuleECommerce.Instance.Strings.GetValue("OrderTotalExcludingArticlesConditionExcludeProductSets", languageID, true));
foreach (Guid item in m_data.SelectedIDs)
{
var productSet = item.GetProductList();
if (productSet != null)
{
sb.Append(Environment.NewLine);
sb.Append(productSet.GetDisplayName(languageID));
}
}
break;
}
description = sb.ToString();
}
else
{
description = base.GetDescription(languageID);
}
}
catch (Exception)
{
description = base.GetDescription(languageID);
}
return description;
}
}
}
Back to top
In your website project, create the web-user control OrderTotalExcludingArticlesConditionControl.ascx and implement it in the IUIExtensionPanel interface. Place the control in the ~/Site/ECommerce/Campaigns/KC/ folder.
The UI of the condition looks as shown below and is rendered from the ~/Site/ECommerce/Campaigns/KC/OrderTotalExcludingArticlesConditionControl.ascx web-user control.

Here is the complete source code of the .ascx file:
<%@ Control Language="C#" AutoEventWireup="true" Codebehind="OrderTotalExcludingArticlesConditionControl.ascx.cs"
Inherits="Web.Site.ECommerce.Campaigns.KC.OrderTotalExcludingArticlesConditionControl" %>
<div style="float:left; margin-right: 25px;">
<div style="display: inline-block;">
<div class="litBoldHeader">
<Foundation:ModuleString ID="ModuleStringOrderTotal" Name="OrderTotalExcludingArticlesConditionOrderTotal" runat="server" />
</div>
<asp:DropDownList ID="c_conditionDropDownList" runat="server" Style="width: 204px;" />
<asp:TextBox ID="c_textBoxPay" runat="server" CssClass="lsCampaignConditionsQuantityField" />
<div class="litBoldHeader" style="display: inline;">
<img src="~/LitiumStudio/ECommerce/Images/transparent.gif" runat="server" id="Img2"
style="vertical-align: middle;" class="litIconRequired" alt="" />
</div>
<asp:RequiredFieldValidator Display="Dynamic" ID="c_requiredQuantityValidator" ControlToValidate="c_textBoxPay"
ValidationGroup="addCampaign" runat="server" ErrorMessage="*" />
<asp:RegularExpressionValidator ID="c_regExQuantityValidator" ControlToValidate="c_textBoxPay"
ValidationGroup="addCampaign" runat="server" ValidationExpression="^\d*[0-9](|.\d*[0-9]|,\d*[0-9])?$"
ErrorMessage="*" />
<div>
<div class="litBoldHeader" style="display: inline;">
<asp:CheckBox CssClass="litInputCheckbox" ID="c_includeVat" runat="server" />
<asp:Label ID="c_includeVatLabel" AssociatedControlID="c_includeVat" runat="server">
<Foundation:ModuleString ID="ModuleString11" Name="TotalIncludingVAT" runat="server" />
</asp:Label>
</div>
<div class="litBoldHeader">
<Foundation:ModuleString ID="ModuleStringOrderTotalExcludingArticlesConditionExcludeArticles" Name="OrderTotalExcludingArticlesConditionExcludeArticles" runat="server" />
</div>
</div>
</div>
<div class="litBoldHeader group" style="width: 450px;">
<div style="float: left;" class="lsCampaignActionReducePriceByAPercentage">
<asp:RadioButtonList RepeatDirection="Vertical" runat="server" RepeatColumns="4"
AutoPostBack="true" ID="c_selectionRadiobuttonlist" OnSelectedIndexChanged="OnDialogSelectionSelectedIndexChanged">
</asp:RadioButtonList>
</div>
<div style="float: right;">
<asp:LinkButton CssClass="litIconPopUp litContentPager" runat="server" Style="float: right;
font-size: 100%;" ID="c_buttonAdd"><foundation:ModuleString runat="server" Name="ButtonAdd"/></asp:LinkButton></div>
</div>
<div id="c_articlesDiv" runat="server">
<div style="clear: both;">
</div>
<LS:GridHelperAjax runat="server" ID="m_articlesHelper" AssociatedControlID="c_articlesGrid"
OnNeedData="ArticleRadGridGetData" DataKeyName="ID" PageSize="5" AllowSorting="true" />
<Telerik:RadGrid ID="c_articlesGrid" CssClass="ArticleGrid" runat="server" Style="height: 168px;
width: 450px; border: solid 1px #CFCDCC;" OnPageIndexChanged="GridPageIndexChanged" AllowMultiRowSelection="true" OnItemCommand="GridItemCommand">
<MasterTableView runat="server" ClientDataKeyNames="ID" CssClass="AutoShrink">
<Columns>
<Telerik:GridBoundColumn DataField="ID" Display="false" />
<Telerik:GridBoundColumn DataField="DisplayName" />
<Telerik:GridBoundColumn DataField="ArticleNumber" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/Litium/Images/svg/times.svg"
ButtonType="ImageButton" UniqueName="DeleteColumn">
<HeaderStyle Width="27px" />
</Telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</Telerik:RadGrid>
</div>
<div id="c_productGroupDiv" runat="server">
<div style="clear: both;">
</div>
<LS:GridHelperAjax runat="server" ID="m_productGroupHelper" AssociatedControlID="c_productGroupsGrid"
OnNeedData="ProductGroupsGridGetData" DataKeyName="ID" PageSize="5" AllowSorting="true" />
<Telerik:RadGrid ID="c_productGroupsGrid" CssClass="ArticleGrid" runat="server" Style="height: 168px;
width: 450px; border: solid 1px #CFCDCC;" OnPageIndexChanged="GridPageIndexChanged" AllowMultiRowSelection="true" OnItemCommand="GridItemCommand">
<MasterTableView runat="server" ClientDataKeyNames="ID" CssClass="AutoShrink">
<Columns>
<Telerik:GridBoundColumn DataField="ID" Display="false" />
<Telerik:GridBoundColumn DataField="DisplayName" />
<Telerik:GridBoundColumn DataField="Assortment" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/Litium/Images/svg/times.svg"
ButtonType="ImageButton" UniqueName="DeleteColumn">
<HeaderStyle Width="27px" />
</Telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</Telerik:RadGrid>
</div>
<div id="c_assortmentDiv" runat="server">
<div style="clear: both;">
</div>
<LS:GridHelperAjax runat="server" ID="c_assortmentGridHelper" AssociatedControlID="c_assortmentGrid"
OnNeedData="AssortmentGridGetData" DataKeyName="ID" PageSize="5" AllowSorting="true" />
<Telerik:RadGrid ID="c_assortmentGrid" CssClass="ArticleGrid" runat="server" Style="height: 168px;
width: 450px; border: solid 1px #CFCDCC;" OnPageIndexChanged="GridPageIndexChanged" AllowMultiRowSelection="true" OnItemCommand="GridItemCommand">
<MasterTableView runat="server" ClientDataKeyNames="ID" CssClass="AutoShrink">
<Columns>
<Telerik:GridBoundColumn DataField="ID" Display="false" />
<Telerik:GridBoundColumn DataField="DisplayName" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/Litium/Images/svg/times.svg"
ButtonType="ImageButton" UniqueName="DeleteColumn">
<HeaderStyle Width="27px" />
</Telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</Telerik:RadGrid>
</div>
<div id="c_productSetDiv" runat="server">
<div style="clear: both;">
</div>
<LS:GridHelperAjax runat="server" ID="m_productSetsHelper" AssociatedControlID="c_productSetsGrid"
OnNeedData="ProductSetsGridGetData" DataKeyName="ID" PageSize="5" AllowSorting="true" />
<Telerik:RadGrid ID="c_productSetsGrid" CssClass="ArticleGrid" runat="server" Style="height: 168px;
width: 450px; border: solid 1px #CFCDCC;" OnPageIndexChanged="GridPageIndexChanged" AllowMultiRowSelection="true" OnItemCommand="GridItemCommand">
<MasterTableView runat="server" ClientDataKeyNames="ID" CssClass="AutoShrink">
<Columns>
<Telerik:GridBoundColumn DataField="ID" Display="false" />
<Telerik:GridBoundColumn DataField="DisplayName" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/Litium/Images/svg/times.svg"
ButtonType="ImageButton" UniqueName="DeleteColumn">
<HeaderStyle Width="27px" />
</Telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</Telerik:RadGrid>
</div>
</div>
<div style="float: left;">
<div class="litBoldHeader">
<Foundation:ModuleString ID="ModuleString3" Name="CampaignDescription" runat="server" />
<img src="~/LitiumStudio/ECommerce/Images/transparent.gif" visible="false" runat="server"
id="Img4" style="vertical-align: middle;" class="litIconRequired" alt="" /></div>
<div class="litText" style="width: 280px;">
<Foundation:ModuleString ID="ModuleString1" Name="OrderTotalExcludingArticlesConditionDescription" runat="server" />
</div>
</div>
<div class="clearer" />
<asp:HiddenField runat="server" ID="c_hiddenFieldIDs" />
Here is the Codebehind file:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns;
using Litium.Studio.UI.Common;
using Litium.Studio.UI.Common.Carriers;
using Litium.Studio.UI.ECommerce.Common;
using Litium.Studio.UI.ECommerce.Common.Constants;
using Telerik.Web.UI;
using Litium;
using Litium.Products;
using Litium.Foundation.Modules.ProductCatalog;
using Litium.Studio.KC.Samples.Campaigns;
namespace Web.Site.ECommerce.Campaigns.KC
{
public partial class OrderTotalExcludingArticlesConditionControl : UserBaseControl, IUIExtensionPanel
{
private const string IS_GREATER_THAN_OR_EQUAL = "IsGreaterThanOrEqual";
private const string IS_LESS_THAN_OR_EQUAL = "IsLessThanOrEqual";
protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);
InitializePageControls();
base.OnInit(e);
Controls.Add(LoadControl("~/Litium/WebUserControls/ProductCatalogDialog.ascx"));
}
protected override object SaveControlState()
{
return m_data;
}
protected override void LoadControlState(object state)
{
if (state != null)
{
m_data = state as OrderTotalExcludingArticlesCondition.Data;
}
}
protected static class DialogType
{
public const string SELECT_ARTICLE = "7";
public const string SELECT_ASSORTMENT = "3";
public const string SELECT_PRODUCT_GROUP = "4";
public const string SELECT_PRODUCT_SET = "5";
}
private readonly Guid PROPERTY_ID = new Guid("61B3AB55-3B97-4B48-820C-E69C981ACB54");
/// <summary>
/// DataField name of display name column.
/// </summary>
private const string DISPLAY_NAME_COLUMN = "DisplayName";
/// <summary>
/// DataField name of article number column.
/// </summary>
private const string ARTICLE_NUMBER_COLUMN = "ArticleNumber";
/// <summary>
/// DataField name of assortment column.
/// </summary>
private const string ASSORTMENT_COLUMN = "Assortment";
private CategoryService _categoryService = IoC.Resolve<CategoryService>();
private AssortmentService _assortmentService = IoC.Resolve<AssortmentService>();
OrderTotalExcludingArticlesCondition.Data Data
{
set
{
m_data = value;
}
get
{
if (m_data == null)
return m_data = new OrderTotalExcludingArticlesCondition.Data { SelectedIDs = new List<Guid>(), SelectedIdType = OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Variants };
return m_data;
}
}
private OrderTotalExcludingArticlesCondition.Data m_data;
private Hashtable SelectedItemIds
{
set
{
Session[ProductCatalogItemCarrier.SESSION_KEY_SELECTED_ITEMS] = value;
if (value != null)
Session[ProductCatalogItemCarrier.SESSION_KEY_SELECTED_EXTRA_ITEMS]
= new Hashtable { { PROPERTY_ID, value[PROPERTY_ID] } };
}
}
private string CampaignSelectedWebSite
{
get
{
string result = string.Empty;
if (Session[SessionConstants.ECOM_CAMPAIGNS_SELECTED_WEBSITE] != null)
{
result = Session[SessionConstants.ECOM_CAMPAIGNS_SELECTED_WEBSITE] as string;
}
return result;
}
}
/// <summary>
/// Initializes the validation on page.
/// </summary>
private void InitializeValidation()
{
c_regExQuantityValidator.CssClass = ParameterConstants.VALIDATOR_STYLE_NAME;
c_regExQuantityValidator.Text = String.Format("{0} {1}", ParameterConstants.VALIDATOR_IMAGE,
SystemStrings.GetValue(SystemStringConstants.VALIDATION_MESSAGE_INVALID_INPUT,
FoundationContext.LanguageID, true));
String digitsSeparator = FoundationContext.Culture.NumberFormat.CurrencyDecimalSeparator;
c_regExQuantityValidator.ValidationExpression = String.Format(@"^\d*[0-9](|\{0}\d*[0-9])?$", digitsSeparator);
c_requiredQuantityValidator.CssClass = ParameterConstants.VALIDATOR_STYLE_NAME;
c_requiredQuantityValidator.Text = String.Format("{0} {1}", ParameterConstants.VALIDATOR_IMAGE,
SystemStrings.GetValue(SystemStringConstants.VALIDATION_MESSAGE_REQUIRED_FIELD,
FoundationContext.LanguageID, true));
}
/// <summary>
/// Initializes the condition drop down.
/// </summary>
private void InitializeConditionDropDown()
{
if (c_conditionDropDownList.Items.Count == 0)
{
String text = CurrentModule.Strings.GetValue(IS_GREATER_THAN_OR_EQUAL, FoundationContext.LanguageID, true);
c_conditionDropDownList.Items.Add(new ListItem(text, IS_GREATER_THAN_OR_EQUAL));
text = CurrentModule.Strings.GetValue(IS_LESS_THAN_OR_EQUAL, FoundationContext.LanguageID, true);
c_conditionDropDownList.Items.Add(new ListItem(text, IS_LESS_THAN_OR_EQUAL));
}
}
/// <summary>
/// Initializes the grids columns.
/// </summary>
private void InitializeGridsColumns()
{
ModuleProductCatalog pcModule = ModuleProductCatalog.Instance;
string columnName = FoundationContext.SystemStrings.GetValue("Name", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_articlesGrid.MasterTableView.Columns.FindByDataField(DISPLAY_NAME_COLUMN).HeaderText = columnName;
columnName = pcModule.Strings.GetValue("ArticleNumber", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_articlesGrid.MasterTableView.Columns.FindByDataField(ARTICLE_NUMBER_COLUMN).HeaderText = columnName;
columnName = pcModule.Strings.GetValue("Name", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_productGroupsGrid.MasterTableView.Columns.FindByDataField(DISPLAY_NAME_COLUMN).HeaderText = columnName;
columnName = pcModule.Strings.GetValue("Location", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_productGroupsGrid.MasterTableView.Columns.FindByDataField(ASSORTMENT_COLUMN).HeaderText = columnName;
columnName = pcModule.Strings.GetValue("Name", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_assortmentGrid.MasterTableView.Columns.FindByDataField(DISPLAY_NAME_COLUMN).HeaderText = columnName;
columnName = pcModule.Strings.GetValue("Name", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_productSetsGrid.MasterTableView.Columns.FindByDataField(DISPLAY_NAME_COLUMN).HeaderText = columnName;
}
/// <summary>
/// Initializes the popup window dialog.
/// </summary>
private void InitializePopupWindowsDialog()
{
HideGrids();
String gridClientId = ConfigureGrids();
if (ModuleProductCatalog.ExistsInstance)
{
c_buttonAdd.Attributes.Add(ParameterConstants.JAVASCRIPT_ON_CLICK,
String.Format("OpenSelectFromProductCatalogGridResult('', '{0}', '', '{1}', '1', '0', '', '', '{2}','','{3}','{4}'); return false;",
c_hiddenFieldIDs.ClientID, c_selectionRadiobuttonlist.SelectedValue, gridClientId, PROPERTY_ID, CampaignSelectedWebSite));
}
else
{
c_buttonAdd.Visible = false;
}
}
/// <summary>
/// Initializes the radio button list control.
/// </summary>
private void InitializeRadioButtonListControl()
{
c_selectionRadiobuttonlist.Items.Clear();
var item = new ListItem();
item.Value = DialogType.SELECT_ARTICLE;
item.Text = CurrentModule.Strings.GetValue("CampaignProducts", FoundationContext.LanguageID, true).Replace(" ", " ");
c_selectionRadiobuttonlist.Items.Add(item);
item = new ListItem();
item.Value = DialogType.SELECT_PRODUCT_GROUP;
item.Text = CurrentModule.Strings.GetValue("CampaignProductGroups", FoundationContext.LanguageID, true).Replace(" ", " ");
c_selectionRadiobuttonlist.Items.Add(item);
item = new ListItem();
item.Value = DialogType.SELECT_ASSORTMENT;
item.Text = CurrentModule.Strings.GetValue("CampaignAssortments", FoundationContext.LanguageID, true).Replace(" ", " ");
c_selectionRadiobuttonlist.Items.Add(item);
item = new ListItem();
item.Value = DialogType.SELECT_PRODUCT_SET;
item.Text = CurrentModule.Strings.GetValue("CampaignProductSets", FoundationContext.LanguageID, true).Replace(" ", " ");
c_selectionRadiobuttonlist.Items.Add(item);
switch (Data.SelectedIdType)
{
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Assortments:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_ASSORTMENT).Selected = true;
break;
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Categories:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_PRODUCT_GROUP).Selected = true;
break;
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.ProductLists:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_PRODUCT_SET).Selected = true;
break;
default:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_ARTICLE).Selected = true;
break;
}
}
/// <summary>
/// Configures the grids on page.
/// </summary>
/// <param name="selectedIdType">Type of the selection criteria.</param>
/// <returns>Grid client ID and popup dialog type</returns>
private string ConfigureGrids()
{
switch (c_selectionRadiobuttonlist.SelectedValue)
{
case DialogType.SELECT_PRODUCT_SET:
{
Data.SelectedIdType = OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.ProductLists;
c_productSetDiv.Attributes.CssStyle.Add("display", "block");
return c_productSetsGrid.ClientID;
}
case DialogType.SELECT_ASSORTMENT:
{
Data.SelectedIdType = OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Assortments;
c_assortmentDiv.Attributes.CssStyle.Add("display", "block");
return c_assortmentGrid.ClientID;
}
case DialogType.SELECT_PRODUCT_GROUP:
{
Data.SelectedIdType = OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Categories;
c_productGroupDiv.Attributes.CssStyle.Add("display", "block");
return c_productGroupsGrid.ClientID;
}
default:
{
Data.SelectedIdType = OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Variants;
c_articlesDiv.Attributes.CssStyle.Add("display", "block");
return c_articlesGrid.ClientID;
}
}
}
/// <summary>
/// Hides the grids div.
/// </summary>
private void HideGrids()
{
c_articlesDiv.Attributes.CssStyle.Add("display", "none");
c_productGroupDiv.Attributes.CssStyle.Add("display", "none");
c_assortmentDiv.Attributes.CssStyle.Add("display", "none");
c_productSetDiv.Attributes.CssStyle.Add("display", "none");
}
/// <summary>
/// Rebinds (clearing) the grids when Selection type is changed.
/// </summary>
private void RebindGrids()
{
Data.SelectedIDs.Clear();
if (c_selectionRadiobuttonlist.SelectedValue == DialogType.SELECT_ASSORTMENT)
c_assortmentGrid.Rebind();
if (c_selectionRadiobuttonlist.SelectedValue == DialogType.SELECT_PRODUCT_GROUP)
c_productGroupsGrid.Rebind();
if (c_selectionRadiobuttonlist.SelectedValue == DialogType.SELECT_PRODUCT_SET)
c_productSetsGrid.Rebind();
if (c_selectionRadiobuttonlist.SelectedValue == DialogType.SELECT_ARTICLE)
c_articlesGrid.Rebind();
}
/// <summary>
/// Processing the hidden field.
/// Retrieve data from hidden field and setting them to Data object.
/// </summary>
private void ProcessingHiddenField()
{
var selectedIDs = new List<Guid>(GetGuidValueList(c_hiddenFieldIDs.Value));
if (selectedIDs.Count != 0)
{
Data.SelectedIDs = Data.SelectedIDs.Concat(selectedIDs).Distinct().ToList();
}
var hashtable = new Hashtable { { PROPERTY_ID, Data.SelectedIDs } };
SelectedItemIds = hashtable;
}
/// <summary>
/// Sorting ProductsSet collection.
/// </summary>
/// <param name="productSets">The product sets.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>Sorted collection.</returns>
private List<ProductList> ProductSetSorting(List<ProductList> productSets, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
productSets.Sort((a, b) => string.Compare(a.Localizations.CurrentCulture.Name, b.Localizations.CurrentCulture.Name));
break;
}
if (sortexpressions[0].SortDirection == SortDirection.Descending)
productSets.Reverse();
return productSets;
}
/// <summary>
/// Sorting Assortment collection.
/// </summary>
/// <param name="assortments">The assortment collection.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns> Sorted collection. </returns>
private List<Assortment> AssortmenSorting(List<Assortment> assortments, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
assortments.Sort((a, b) => string.Compare(a.Localizations.CurrentCulture.Name, b.Localizations.CurrentCulture.Name));
break;
}
if (sortexpressions[0].SortDirection == SortDirection.Descending)
assortments.Reverse();
return assortments;
}
/// <summary>
/// Sorting for ProductGroup collection.
/// </summary>
/// <param name="productGroups">The product groups.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>Sorted collection.</returns>
private List<Category> ProductGroupSorting(List<Category> productGroups, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
productGroups.Sort((a, b) => string.Compare(a.Localizations.CurrentCulture.Name, b.Localizations.CurrentCulture.Name));
break;
case ASSORTMENT_COLUMN:
productGroups.Sort((a, b) => string.Compare(a.Localizations.CurrentCulture.Name, b.Localizations.CurrentCulture.Name));
break;
}
if (sortexpressions[0].SortDirection == SortDirection.Descending)
productGroups.Reverse();
return productGroups;
}
/// <summary>
/// Sorting Articles collection.
/// </summary>
/// <param name="articles">The articles.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>Sorted collection.</returns>
private List<Variant> ArticleSorting(List<Variant> articles, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
articles.Sort((a, b) => string.Compare(a.Localizations.CurrentCulture.Name, b.Localizations.CurrentCulture.Name));
break;
case ARTICLE_NUMBER_COLUMN:
articles.Sort((a, b) => a.Id.CompareTo(b.Id));
break;
}
if (sortexpressions[0].SortDirection == SortDirection.Descending)
articles.Reverse();
return articles;
}
protected override void Page_Load(object sender, EventArgs e)
{
InitializePopupWindowsDialog();
}
/// <summary>
/// Initializes the page controls.
/// </summary>
private void InitializePageControls()
{
InitializeConditionDropDown();
InitializeRadioButtonListControl();
InitializeValidation();
InitializeGridsColumns();
}
/// <summary>
/// Articles the RAD grid getting data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="startrowindex">The start row index.</param>
/// <param name="pagesize">The page size.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>PageResult object.</returns>
protected PagedResult ArticleRadGridGetData(object sender, int startrowindex, int pagesize, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
ProcessingHiddenField();
var articlesCollection = new List<Variant>();
if (Data.SelectedIDs.Count > 0)
{
var variantService = IoC.Resolve<VariantService>();
foreach (Guid articleID in Data.SelectedIDs)
{
var article = variantService.Get(articleID);
if (article != null)
{
articlesCollection.Add(article);
}
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
articlesCollection = ArticleSorting(articlesCollection, sortexpressions);
return new PagedResult
{
Count = articlesCollection.Count,
Data = articlesCollection.Select(x => new ReducePriceByPercentageResult { ID = x.SystemId, DisplayName = x.Localizations.CurrentCulture.Name, ArticleNumber = x.Id }).ToList(),
Reset = pagesize > startrowindex
};
}
/// <summary>
/// Products groups grid get data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="startrowindex">The start row index.</param>
/// <param name="pagesize">The page size.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>PageResult object.</returns>
protected PagedResult ProductGroupsGridGetData(object sender, int startrowindex, int pagesize, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
ProcessingHiddenField();
var productGroups = new List<Category>();
if (Data.SelectedIDs.Count > 0)
{
foreach (Guid id in Data.SelectedIDs)
{
var item = _categoryService.Get(id);
if (item != null)
productGroups.Add(item);
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
productGroups = ProductGroupSorting(productGroups, sortexpressions);
var pageResult = new PagedResult
{
Count = productGroups.Count,
Reset = pagesize > startrowindex
};
pageResult.Data = productGroups.Select(x =>
new ReducePriceByPercentageResult
{
ID = x.SystemId,
DisplayName = x.Localizations.CurrentCulture.Name,
Assortment = GetCategoryPath(x.SystemId)
}).ToList();
return pageResult;
}
/// <summary>
/// Assortment grid get data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="startrowindex">The start row index.</param>
/// <param name="pagesize">The page size.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>PageResult object.</returns>
protected PagedResult AssortmentGridGetData(object sender, int startrowindex, int pagesize, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
ProcessingHiddenField();
var assortments = new List<Assortment>();
if (Data.SelectedIDs.Count > 0)
{
foreach (Guid id in Data.SelectedIDs)
{
var item = _assortmentService.Get(id);
if (item != null)
assortments.Add(item);
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
assortments = AssortmenSorting(assortments, sortexpressions);
return new PagedResult
{
Count = assortments.Count,
Reset = pagesize > startrowindex,
Data = assortments.Select(x => new ReducePriceByPercentageResult { ID = x.SystemId, DisplayName = x.Localizations.CurrentCulture.Name }).ToList()
};
}
/// <summary>
/// ProductSet grid get data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="startrowindex">The start row index.</param>
/// <param name="pagesize">The page size.</param>
/// <param name="sortexpressions">The sort expressions.</param>
/// <returns>PageResult object.</returns>
protected PagedResult ProductSetsGridGetData(object sender, int startrowindex, int pagesize, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
ProcessingHiddenField();
var productSets = new List<ProductList>();
if (Data.SelectedIDs.Count > 0)
{
var productSetService = IoC.Resolve<ProductListService>();
foreach (Guid id in Data.SelectedIDs)
{
var productSet = productSetService.Get<ProductList>(id);
if (productSet != null)
productSets.Add(productSet);
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
productSets = ProductSetSorting(productSets, sortexpressions);
return new PagedResult
{
Count = productSets.Count,
Reset = pagesize > startrowindex,
Data = productSets.Select(x => new
{
ID = x.SystemId,
DisplayName = x.Localizations.CurrentCulture.Name,
}).ToList()
};
}
/// <summary>
/// Called when GridItemCommand event raised.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="e">The <see cref="Telerik.Web.UI.GridCommandEventArgs"/> instance containing the event data.</param>
protected void GridItemCommand(object source, GridCommandEventArgs e)
{
if (e.CommandName == "RebindGrid") return;
if (e.CommandName == "Delete")
{
Guid deletableItemID = Guid.Empty;
switch (Data.SelectedIdType)
{
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Assortments:
deletableItemID = (Guid)c_assortmentGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.Categories:
deletableItemID = (Guid)c_productGroupsGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
case OrderTotalExcludingArticlesCondition.Data.SelectionCriteria.ProductLists:
deletableItemID = (Guid)c_productSetsGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
default:
deletableItemID = (Guid)c_articlesGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
}
if (deletableItemID != Guid.Empty)
Data.SelectedIDs.Remove(deletableItemID);
}
c_hiddenFieldIDs.Value = string.Join(",", Data.SelectedIDs.ToList().ConvertAll(x => x.ToString()).ToArray());
}
/// <summary>
/// Gets the GUID value list.
/// </summary>
/// <param name="originalValue">The comma separated Guid-string value.</param>
/// <returns>IEnumerable Guid collection.</returns>
private static IEnumerable<Guid> GetGuidValueList(string originalValue)
{
string[] values = originalValue.Split(ParameterConstants.VALUE_SEPERATOR_COMMA);
return (values.Where(value => !string.IsNullOrEmpty(value)).Select(value => new Guid(value))).ToList();
}
/// <summary>
/// Called when [select type checked changed] event raised.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void OnDialogSelectionSelectedIndexChanged(object sender, EventArgs e)
{
c_hiddenFieldIDs.Value = String.Empty;
RebindGrids();
InitializePopupWindowsDialog();
SelectedItemIds = null;
}
/// <summary>
/// Gets the panel data.
/// </summary>
/// <returns>Return an object with the panel data.</returns>
object IUIExtensionPanel.GetPanelData()
{
decimal totalPrice;
decimal.TryParse(c_textBoxPay.Text, out totalPrice);
Data.TotalPrice = totalPrice;
Data.IncludeVat = c_includeVat.Checked;
Data.ShouldBeEqualOrMore = c_conditionDropDownList.Items.FindByValue(IS_GREATER_THAN_OR_EQUAL).Selected;
return Data;
}
/// <summary>
/// Sets the panel data.
/// </summary>
/// <param name="data">The data.</param>
void IUIExtensionPanel.SetPanelData(object data)
{
if (data is OrderTotalExcludingArticlesCondition.Data)
Data = (OrderTotalExcludingArticlesCondition.Data)data;
InitializePageControls();
if (data is OrderTotalExcludingArticlesCondition.Data)
{
c_hiddenFieldIDs.Value = string.Join(",", Data.SelectedIDs.ToList().ConvertAll(x => x.ToString()).ToArray());
c_textBoxPay.Text = Data.TotalPrice.ToString();
c_includeVat.Checked = Data.IncludeVat;
if (!Data.ShouldBeEqualOrMore)
{
ListItem item = c_conditionDropDownList.Items.FindByValue(IS_LESS_THAN_OR_EQUAL);
if (item != null)
item.Selected = true;
}
}
}
protected void GridPageIndexChanged(object source, GridPageChangedEventArgs e)
{
c_hiddenFieldIDs.Value = string.Join(",", Data.SelectedIDs.ToList().ConvertAll(x => x.ToString()).ToArray());
}
private string GetCategoryPath(Guid categoryId)
{
var category = _categoryService.Get(categoryId);
var currentName = category.Localizations.CurrentCulture.Name ?? category.Id;
if (category.ParentCategorySystemId == Guid.Empty)
{
return _assortmentService.Get(category.AssortmentSystemId).Localizations.CurrentCulture.Name + " > " + currentName;
}
return GetCategoryPath(category.ParentCategorySystemId) + " > " + currentName;
}
}
[Serializable]
internal sealed class ReducePriceByPercentageResult
{
public Guid ID { get; set; }
public string DisplayName { get; set; }
public string ArticleNumber { get; set; }
public string Assortment { get; set; }
}
}
Back to top
Import condition strings to the Sales area.
<ModuleStringCollection>
<Strings>
<ModuleString Key="OrderTotalExcludingArticlesConditionDescription" Value="Total of all order rows (excluding order rows that contains article from above list) should meet this condition" />
<ModuleString Key="OrderTotalExcludingArticlesConditionExcludeArticles" Value="If the order does not contain following products" />
<ModuleString Key="OrderTotalExcludingArticlesConditionExcludeAssortment" Value="If order doesn't contain products that belong to {0} assortment(s)" />
<ModuleString Key="OrderTotalExcludingArticlesConditionExcludeProductGroup" Value="if order does not contain product from the following categories (products in subcategories are not considered)" />
<ModuleString Key="OrderTotalExcludingArticlesConditionExcludeProductSets" Value="if order does not contain product from the following product lists" />
<ModuleString Key="OrderTotalExcludingArticlesConditionName" Value="Order total excluding specified articles" />
<ModuleString Key="OrderTotalExcludingArticlesConditionOrderTotal" Value="Order total excluding specified articles condition" />
</Strings>
</ModuleStringCollection>

Back to top