An action with customized logic can be created by implementing the IAction and IUIExtension interfaces. This article is a step-by-step guide to creating a custom action.
Step 1
Create a separate project in your solution to place your custom classes.
Step 2
In your project create a class and implement the following two interfaces:
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.IAction
- Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.IUIExtension
The user interface for your action should be created in the asp.net user control (.ascx) which implements the IUIExtensionPanel interface. The path to this user control should be returned by the IUIExtension.PanelPath property implementation.
Example: Reduce the price of an article by a fixed amount
The following example extends the default IAction implementation called CampaignAction to create a new "product campaign" action that reduces the price by a certain amount. This action is useful in scenarios where a price reduction by a certain percentage is regarded as unattractive by the end customers. For example, if a set of products are priced at 110 SEK each, giving a 10% price reduction would result in a fractional unit price. However, if the price can be set to 99SEK by a simple reduction of 11 SEK, it gives a better user appeal.
The class definition would look as follows: (where CampaignAction is from the namespace Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.Actions)
public class ReducePriceByAmountAction : CampaignAction
{
//Custom implementation code here...
}
Action UI
When a campaign is created in back office, the user needs to configure it by entering the reduction amount. The following is the UI we intend to build for this action.

The user control that renders this UI is placed into the ~/Site/ECommerce/Campaigns/KC/ folder and is named ReducePriceByAmountActionControl.ascx. This user control needs to implement the interface IUIExtensionPanel from the Litium.Foundation.Modules.ECommerce.Plugins.Campaigns namespace.
The IUIExtensionPanel interface has methods that will make it possible to get and set data from the UI.
Custom data
The campaign action needs custom data to perform its action. As shown in the above image, data such as the discount amount, the set of articles or product groups that the campaign should apply to, and whether to apply the price reduction on an existing campaign price or not, needs to be collected and stored. To keep this information a class is defined called Data as a sub-class inside the ReducePriceByAmountAction class. This class has the following format (note how it corresponds to the UI shown in the above image):
public class ReducePriceByAmountAction : CampaignAction
{
/// <summary>
/// Action data subclass
/// </summary>
[Serializable]
public class Data
{
/// <summary>
/// Define the type of Ids selected for the <see cref="Data.SelectedIDs"/> property.
/// </summary>
public enum SelectionCriteria
{
/// <summary>
/// Article ids
/// </summary>
Articles,
/// <summary>
/// Product group íds
/// </summary>
ProductGroups,
/// <summary>
/// Assortment ids.
/// </summary>
Assortments,
/// <summary>
/// product set ids.
/// </summary>
ProductSets
}
/// <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 or sets the discount amount.
/// </summary>
/// <value>The discount percentage.</value>
public decimal DiscountAmountWithVAT { get; set; }
/// <summary>
/// If true, if there is already a campaign price, this campaign will discount that price.
/// If there is no campaign price when this campaign is processed, list price will be used.
/// </summary>
/// <value>The apply on campaign price cumulatively.</value>
public bool ApplyOnCampaignPriceCumulatively { get; set; }
/// <summary>
/// Gets or sets the max discounts per item in order.
/// </summary>
/// <value>
/// The max discounts per item in order.
/// </value>
public int MaxDiscountsPerItemInOrder { get; set; }
}
}
The web user control ~/Site/ECommerce/Campaigns/KC/ReducePriceByAmountActionControl.ascx is initialized using an object of the above class, using the IUIExtensionPanel implementation.

For example, the GetPanelData and SetPanelData implementations shown in the above image would look as follows:
#region Implementation of IUIExtensionPanel
/// <summary>
/// Gets the panel data.
/// </summary>
/// <returns>Return an object with the panel data.</returns>
object IUIExtensionPanel.GetPanelData()
{
decimal amount;
Data.ApplyOnCampaignPriceCumulatively = c_applyOnCampaignCheckbox.Checked;
decimal.TryParse(c_textboxAmount.Text, out amount);
Data.DiscountAmountWithVAT = amount;
int maxDiscountsPerItemInOrder;
if (int.TryParse(c_textboxMaxDiscountsPerItemInOrder.Text, out maxDiscountsPerItemInOrder))
Data.MaxDiscountsPerItemInOrder = maxDiscountsPerItemInOrder;
else
Data.MaxDiscountsPerItemInOrder = -1;
return Data;
}
/// <summary>
/// Sets the panel data.
/// </summary>
/// <param name="data">The data.</param>
void IUIExtensionPanel.SetPanelData(object data)
{
if (data is ReducePriceByAmountAction.Data)
Data = (ReducePriceByAmountAction.Data)data;
InitializePageControls();
if (data is ReducePriceByAmountAction.Data)
{
c_applyOnCampaignCheckbox.Checked = Data.ApplyOnCampaignPriceCumulatively;
c_textboxAmount.Text = Data.DiscountAmountWithVAT.ToString();
c_textboxMaxDiscountsPerItemInOrder.Text = (Data.MaxDiscountsPerItemInOrder > 0) ? Data.MaxDiscountsPerItemInOrder.ToString() : string.Empty;
switch (Data.SelectedIdType)
{
case ReducePriceByAmountAction.Data.SelectionCriteria.Assortments:
c_assortmentGrid.Rebind();
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups:
c_productGroupsGrid.Rebind();
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets:
c_productSetsGrid.Rebind();
break;
default:
c_articlesGrid.Rebind();
break;
}
}
}
#endregion
IAction.Initialize(object data) method
This method is called by the Litium API to initialize the campaign action with data saved when configuring it. The parameter data is of the type ReducePriceByAmountAction.Data.
This method is called when the Activate button is clicked for the campaign, or at application load time for activated campaigns to initialize the action with data saved while configuring the campaign.

IAction.Process() method
This method is called when the campaign engine evaluates a specific campaign. This method should change the orderCarrier in the ActionArgs and return true when the campaign is applied or return false when it is not applied.
IAction.GetConditions() method
This method allows the action to define its own conditions, to pre-evaluate whether an action can be performed or not. Since the above example action will apply only to selected set of articles, or product groups, or assortments or product sets, a set of campaign conditions can be built by the action itself and provided to the campaign engine through this method. This allows the campaign engine to optimize performance.
protected override IList<ICondition> GetConditions()
{
ICondition condition = null;
switch(_mData.SelectedIdType)
{
case Data.SelectionCriteria.Articles:
condition = new ArticleCondition();
condition.Initialize(new ArticleCondition.Data { ArticleIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.Assortments:
condition = new AssortmentCondition();
condition.Initialize(new AssortmentCondition.Data { AssortmentIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.ProductGroups:
condition = new ProductGroupCondition();
condition.Initialize(new ProductGroupCondition.Data { ProductGroupIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.ProductSets:
condition = new ProductSetCondition();
condition.Initialize(new ProductSetCondition.Data { ProductSetIDs = _mData.SelectedIDs, FilterRows = true });
break;
}
return new[] { condition };
}
IAction.ActionType property
This property determines the type of the campaign.
The complete source of the above example is presented below. For the action to get loaded, place the .dll file that contains the ReducePriceByAmountAction class into the web\bin directory. Litium IoC will automatically detect the action and load it into the Action drop-down list.

ReducePriceByAmountAction.cs class
This class is placed into the C# assembly project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Litium.Foundation.Modules.ECommerce;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.Actions;
using Litium.Foundation.Modules.ECommerce.Plugins.Campaigns.Conditions;
using Litium.Foundation.Modules.ProductCatalog.Articles;
using Litium.Foundation.Modules.ProductCatalog.Assortments;
using Litium.Foundation.Modules.ProductCatalog.Products;
using Litium.Foundation.Modules.ProductCatalog.ProductSets;
using Litium.Foundation.Security;
namespace Litium.Studio.KC.Samples.Campaigns
{
/// <summary>
/// Reduces the article campaign price by a percentage.
/// </summary>
public class ReducePriceByAmountAction : CampaignAction
{
Data _mData;
private const string Path = "~/Site/ECommerce/Campaigns/KC/ReducePriceByAmountActionControl.ascx";
/// <summary>
/// Action data.
/// </summary>
[Serializable]
public class Data
{
/// <summary>
/// Define the type of Ids selected for the <see cref="Data.SelectedIDs"/> property.
/// </summary>
public enum SelectionCriteria
{
/// <summary>
/// Article ids
/// </summary>
Articles,
/// <summary>
/// Product group íds
/// </summary>
ProductGroups,
/// <summary>
/// Assortment ids.
/// </summary>
Assortments,
/// <summary>
/// product set ids.
/// </summary>
ProductSets
}
/// <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 or sets the discount amount.
/// </summary>
/// <value>The discount percentage.</value>
public decimal DiscountAmountWithVAT { get; set; }
/// <summary>
/// If true, if there is already a campaign price, this campaign will discount that price.
/// If there is no campaign price when this campaign is processed, list price will be used.
/// </summary>
/// <value>The apply on campaign price cumulatively.</value>
public bool ApplyOnCampaignPriceCumulatively { get; set; }
/// <summary>
/// Gets or sets the max discounts per item in order.
/// </summary>
/// <value>
/// The max discounts per item in order.
/// </value>
public int MaxDiscountsPerItemInOrder { get; set; }
}
/// <summary>
/// Initializes the specified data.
/// </summary>
/// <param name="data">The data.</param>
protected override void Initialize(object data)
{
base.Initialize(data);
_mData = (Data)data;
}
/// <summary>
/// Gets the conditions that is required for this action.
/// </summary>
/// <returns>
/// A list of <see cref="ICondition"/> that should be added as conditions for the campaign.
/// </returns>
protected override IList<ICondition> GetConditions()
{
ICondition condition = null;
switch(_mData.SelectedIdType)
{
case Data.SelectionCriteria.Articles:
condition = new ArticleCondition();
condition.Initialize(new ArticleCondition.Data { ArticleIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.Assortments:
condition = new AssortmentCondition();
condition.Initialize(new AssortmentCondition.Data { AssortmentIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.ProductGroups:
condition = new ProductGroupCondition();
condition.Initialize(new ProductGroupCondition.Data { ProductGroupIDs = _mData.SelectedIDs, FilterRows = true });
break;
case Data.SelectionCriteria.ProductSets:
condition = new ProductSetCondition();
condition.Initialize(new ProductSetCondition.Data { ProductSetIDs = _mData.SelectedIDs, FilterRows = true });
break;
}
return new[] { condition };
}
/// <summary>
/// Processes the reduce price by amount action.
/// </summary>
/// <remarks>
/// This action might split order rows, or move quantities between similar order rows.
/// </remarks>
/// <param name="actionArgs">The action args.</param>
/// <returns>
/// <c>True</c> if actions is applied, otherwise <c>False</c>.
/// </returns>
protected override bool Process(ActionArgs actionArgs)
{
if (_mData.MaxDiscountsPerItemInOrder > 0)
{
//first give discounts to autogenerated items, ordered by lowest priced items.
//var orderedRows = actionArgs.FilteredOrderRows.OrderByDescending().ThenBy(x => x.OrderRowCarrier.UnitListPrice).ToList();
var articleCount = (from o in actionArgs.FilteredOrderRows
group o by o.ArticleID into g
select new { ArticleId = g.Key, Quantity = 0 }).ToDictionary(x=>x.ArticleId, y=>y.Quantity);
//order by autogenerated, so auto generated are considered last, then order by quantity, so lower quantities taken first to avoid unnecessary splits.
var orderedRows = actionArgs.FilteredOrderRows.OrderByDescending(y => y.OrderRowCarrier.IsAutoGenerated).ThenBy(x=>x.Quantity).ToList();
for (int i = 0; i < orderedRows.Count(); i++)
{
FilteredOrderRow item = orderedRows[i];
if (articleCount[item.ArticleID] < _mData.MaxDiscountsPerItemInOrder)
{
if (articleCount[item.ArticleID] + item.Quantity > _mData.MaxDiscountsPerItemInOrder)
{
int discountQty = _mData.MaxDiscountsPerItemInOrder - articleCount[item.ArticleID];
//find a order row already not considered..
var nextAvailableItem = orderedRows.FirstOrDefault(x => x.OrderRowCarrier.CampaignID != actionArgs.CampaignID && x.OrderRowCarrier.ID != item.OrderRowCarrier.ID
&& x.ProductID == item.ProductID && x.ArticleID == item.ArticleID);
//move items which will not attract discounts to, this already not considered row.
if (nextAvailableItem != null)
{
int qtyToMove = (int)(item.OrderRowCarrier.Quantity - discountQty);
nextAvailableItem.OrderRowCarrier.Quantity += qtyToMove;
item.OrderRowCarrier.Quantity = discountQty;
}
else
{
//Split
CampaignUtils.SplitOrderRow(actionArgs, item, discountQty);
}
}
ApplyCampaignToOrderRow(actionArgs.CampaignID, item);
articleCount[item.ArticleID] += (int)item.Quantity;
}
}
}
else
{
foreach (var item in actionArgs.FilteredOrderRows)
{
ApplyCampaignToOrderRow(actionArgs.CampaignID, item);
}
}
return actionArgs.FilteredOrderRows.Count > 0;
}
/// <summary>
/// Gets the type of the action.
/// </summary>
/// <value>The type of the action.</value>
public override ActionType ActionType
{
get { return ActionType.Product; }
}
/// <summary>
/// Gets the panel path.
/// </summary>
/// <value>The panel path.</value>
public override string PanelPath
{
get { return Path; }
}
/// <summary>
/// Gets the description.
/// </summary>
/// <param name="languageID">The language ID.</param>
/// <returns></returns>
public override string GetDescription(Guid languageID)
{
string description;
try
{
var sb = new StringBuilder();
if (_mData != null)
{
SecurityToken token = ModuleECommerce.Instance.AdminToken;
switch (_mData.SelectedIdType)
{
case Data.SelectionCriteria.Articles:
description = ModuleECommerce.Instance.Strings.GetValue("ReducePriceByAmountActionDescriptionArticle", languageID, true);
sb.AppendFormat(description, _mData.DiscountAmountWithVAT);
foreach (Guid item in _mData.SelectedIDs)
{
if (Article.ExistsArticle(item))
{
sb.Append(Environment.NewLine);
sb.Append("- " + Article.GetArticle(item, token).GetDisplayName(languageID));
}
}
break;
case Data.SelectionCriteria.Assortments:
description = ModuleECommerce.Instance.Strings.GetValue("ReducePriceByAmountActionDescriptionAssortment", languageID, true);
sb.AppendFormat(description, _mData.DiscountAmountWithVAT);
foreach (Guid item in _mData.SelectedIDs)
{
if (Assortment.ExistsCatalog(item))
{
sb.Append(Environment.NewLine);
sb.Append("- " + Assortment.GetAssortment(item, token).GetDisplayName(languageID));
}
}
break;
case Data.SelectionCriteria.ProductGroups:
description = ModuleECommerce.Instance.Strings.GetValue("ReducePriceByAmountActionDescriptionProductGroup", languageID, true);
sb.AppendFormat(description, _mData.DiscountAmountWithVAT);
foreach (Guid item in _mData.SelectedIDs)
{
if (ProductGroup.ExistsProductGroup(item))
{
sb.Append(Environment.NewLine);
sb.Append("- " + ProductGroup.GetProductGroup(item).GetDisplayName(languageID));
}
}
break;
case Data.SelectionCriteria.ProductSets:
description = ModuleECommerce.Instance.Strings.GetValue("ReducePriceByAmountActionDescriptionProductSets", languageID, true);
sb.AppendFormat(description, _mData.DiscountAmountWithVAT);
foreach (Guid item in _mData.SelectedIDs)
{
if (ProductSet.ExistsProductSet(item))
{
sb.Append(Environment.NewLine);
sb.Append("- " + ProductSet.GetProductSet(item, token).GetDisplayName(languageID));
}
}
break;
}
if (_mData.ApplyOnCampaignPriceCumulatively)
{
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
sb.Append(ModuleECommerce.Instance.Strings.GetValue("ReducePriceByAmountActionApplyOnCampaignPrice", languageID, true));
}
if (_mData.MaxDiscountsPerItemInOrder > 0)
{
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
sb.Append(ModuleECommerce.Instance.Strings.GetValue("MaxDiscountsPerOrder", languageID, true));
sb.Append(" = ");
sb.Append(_mData.MaxDiscountsPerItemInOrder);
}
description = sb.ToString();
}
else
{
description = base.GetDescription(languageID);
}
}
catch
{
description = base.GetDescription(languageID);
}
return description;
}
/// <summary>
/// Applies the campaign to order row.
/// </summary>
/// <param name="campaignId">The campaign id.</param>
/// <param name="item">The item.</param>
private void ApplyCampaignToOrderRow(Guid campaignId, FilteredOrderRow item)
{
var discountAmount = Decimal.Divide(_mData.DiscountAmountWithVAT, 1 + item.OrderRowCarrier.VATPercentage);
if (_mData.ApplyOnCampaignPriceCumulatively)
{
item.OrderRowCarrier.UnitCampaignPrice = (item.OrderRowCarrier.CampaignID == Guid.Empty) ?
item.OrderRowCarrier.UnitListPrice - discountAmount:
item.OrderRowCarrier.UnitCampaignPrice - discountAmount;
}
else
{
item.OrderRowCarrier.UnitCampaignPrice = item.OrderRowCarrier.UnitListPrice - discountAmount;
}
if (item.OrderRowCarrier.UnitCampaignPrice < 0)
item.OrderRowCarrier.UnitCampaignPrice = 0;
item.OrderRowCarrier.CampaignID = campaignId;
}
}
}
ReducePriceByAmountActionControl.ascx user control
This is placed in the webroot\Site\ECommerce\Campaigns\ folder.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ReducePriceByAmountActionControl.ascx.cs"
Inherits="Web.Site.ECommerce.Campaigns.KC.ReducePriceByAmountActionControl" %>
<div style="float:left; margin-right: 25px;">
<div>
<div class="litBoldHeader">
<Foundation:ModuleString ID="ModuleStringDiscountAmount" Name="ReducePriceByAmountActionAmount" runat="server" />
<img src="~/LitiumStudio/ECommerce/Images/transparent.gif" runat="server" id="Img3"
style="vertical-align: middle;" class="litIconRequired" alt="" />
</div>
<div>
<div style="display: inline;">
<asp:TextBox ID="c_textboxAmount" runat="server" Width="200" />
</div>
<div style="display: inline; margin-left: 10px;">
<asp:CheckBox CssClass="litInputCheckbox" ID="c_applyOnCampaignCheckbox" runat="server" />
<asp:Label ID="Label1" AssociatedControlID="c_applyOnCampaignCheckbox" runat="server">
<Foundation:ModuleString ID="ModuleStringApplyOnCampaignPrice" Name="ApplyOnCampaignPrice" runat="server" />
</asp:Label>
</div>
</div>
<div class="litBoldHeader">
<Foundation:ModuleString ID="ModuleStringMaxDiscountsPerItemInOrder" Name="MaxDiscountsPerItemInOrder" runat="server" />
</div>
<div>
<div style="display: inline;">
<asp:TextBox ID="c_textboxMaxDiscountsPerItemInOrder" runat="server" Width="200" />
</div>
</div>
<div>
<asp:RequiredFieldValidator Display="Dynamic" ID="c_percentageRequiredValidator"
ValidationGroup="addCampaign" ControlToValidate="c_textboxAmount" runat="server"
ErrorMessage="*" />
<asp:RegularExpressionValidator ID="c_percentageRegexValidator" ControlToValidate="c_textboxAmount"
ValidationGroup="addCampaign" runat="server" ValidationExpression="^\d*[0-9](|.\d*[0-9]|,\d*[0-9])?$"
ErrorMessage="*" />
</div>
</div>
<div class="litBoldHeader" 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="/LitiumStudio/Images/icons_standard/delete.png"
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="Location" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/LitiumStudio/Images/icons_standard/delete.png"
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="/LitiumStudio/Images/icons_standard/delete.png"
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:GridBoundColumn DataField="Assortment" />
<Telerik:GridButtonColumn CommandName="Delete" CommandArgument="ID" ImageUrl="/LitiumStudio/Images/icons_standard/delete.png"
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;">
<asp:Label ID="c_labelDescription" runat="server"></asp:Label>
</div>
</div>
<div class="clearer" />
<asp:HiddenField runat="server" ID="c_hiddenFieldIDs" />
The code-behind file of the above webcontrol:
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.Foundation.Modules.ProductCatalog;
using Litium.Foundation.Modules.ProductCatalog.Articles;
using Litium.Foundation.Modules.ProductCatalog.Assortments;
using Litium.Foundation.Modules.ProductCatalog.Products;
using Litium.Foundation.Modules.ProductCatalog.ProductSets;
using Litium.Studio.KC.Samples.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 SystemStringConstants = Litium.Foundation.GUI.Constants.SystemStringConstants;
namespace Web.Site.ECommerce.Campaigns.KC
{
public partial class ReducePriceByAmountActionControl : UserBaseControl, IUIExtensionPanel
{
#region Control State
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.RegisterRequiresControlState(this);
Controls.Add(LoadControl("~/LitiumStudio/WebUserControls/ProductCatalogDialog.ascx"))
}
protected override object SaveControlState()
{
return _data;
}
protected override void LoadControlState(object state)
{
if (state != null)
{
_data = state as ReducePriceByAmountAction.Data;
}
}
#endregion Control State
#region Constants
protected static class DialogType
{
public const string SELECT_ARTICLE = "1";
public const string SELECT_ASSORTMENT = "3";
public const string SELECT_PRODUCT_GROUP = "4";
public const string SELECT_PRODUCT_SET = "5";
}
/// <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 location column.
/// </summary>
private const string LOCATION_COLUMN = "Location";
/// <summary>
/// DataField name of assortment column.
/// </summary>
private const string ASSORTMENT_COLUMN = "Assortment";
private readonly Guid PROPERTY_ID = new Guid("61B3AB55-3B97-4B48-820C-E69C981ACB54");
#endregion
#region Property
ReducePriceByAmountAction.Data Data
{
set
{
_data = value;
}
get
{
if (_data == null)
return _data = new ReducePriceByAmountAction.Data { SelectedIDs = new List<Guid>(), SelectedIdType = ReducePriceByAmountAction.Data.SelectionCriteria.Articles, MaxDiscountsPerItemInOrder = -1 };
return _data;
}
}
private ReducePriceByAmountAction.Data _data;
private Hashtable SelectedItemIds
{
set
{
Session[ProductCatalogItemCarrier.SESSION_KEY_SELECTED_ITEMS] = value;
Session[ProductCatalogItemCarrier.SESSION_KEY_SELECTED_EXTRA_ITEMS] = value;
}
}
#endregion Property
#region Private Metods
/// <summary>
/// Initializes the validation on page.
/// </summary>
private void InitializeValidation()
{
c_percentageRegexValidator.CssClass = ParameterConstants.VALIDATOR_STYLE_NAME;
c_percentageRegexValidator.Text = String.Format("{0} {1}", ParameterConstants.VALIDATOR_IMAGE,
SystemStrings.GetValue(SystemStringConstants.VALIDATION_MESSAGE_INVALID_INPUT,
FoundationContext.LanguageID, true));
string requiredMessage = String.Format("{0} {1}", ParameterConstants.VALIDATOR_IMAGE,
SystemStrings.GetValue(SystemStringConstants.VALIDATION_MESSAGE_REQUIRED_FIELD,
FoundationContext.LanguageID, true));
c_percentageRequiredValidator.CssClass = ParameterConstants.VALIDATOR_STYLE_NAME;
c_percentageRequiredValidator.Text = requiredMessage;
}
/// <summary>
/// Initialize description of the action.
/// </summary>
private void InitializeDescription()
{
string description = CurrentModule.Strings.GetValue("ReducePriceByAmountActionDescriptionGeneral",
FoundationContext.LanguageID, true);
string selectedType = string.Empty;
switch (Data.SelectedIdType)
{
case ReducePriceByAmountAction.Data.SelectionCriteria.Assortments:
selectedType = CurrentModule.Strings.GetValue("CampaignAssortments", FoundationContext.LanguageID, true).Replace(" ", " ");
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups:
selectedType = CurrentModule.Strings.GetValue("CampaignProductGroups", FoundationContext.LanguageID, true).Replace(" ", " ");
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets:
selectedType = CurrentModule.Strings.GetValue("CampaignProductSets", FoundationContext.LanguageID, true).Replace(" ", " ");
break;
default:
selectedType = CurrentModule.Strings.GetValue("CampaignProducts", FoundationContext.LanguageID, true).Replace(" ", " ");
break;
}
c_labelDescription.Text = string.Format(description, selectedType);
}
/// <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(LOCATION_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;
columnName = pcModule.Strings.GetValue("Location", FoundationContext.LanguageID, true).Replace(" ", " ");
if (!string.IsNullOrEmpty(columnName))
c_productSetsGrid.MasterTableView.Columns.FindByDataField(ASSORTMENT_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', '1', '', '', '{2}','','{3}'); return false;",
c_hiddenFieldIDs.ClientID, c_selectionRadiobuttonlist.SelectedValue, gridClientId, PROPERTY_ID));
}
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 ReducePriceByAmountAction.Data.SelectionCriteria.Assortments:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_ASSORTMENT).Selected = true;
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups:
c_selectionRadiobuttonlist.Items.FindByValue(DialogType.SELECT_PRODUCT_GROUP).Selected = true;
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets:
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 = ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets;
c_productSetDiv.Attributes.CssStyle.Add("display", "block");
return c_productSetsGrid.ClientID;
}
case DialogType.SELECT_ASSORTMENT:
{
Data.SelectedIdType = ReducePriceByAmountAction.Data.SelectionCriteria.Assortments;
c_assortmentDiv.Attributes.CssStyle.Add("display", "block");
return c_assortmentGrid.ClientID;
}
case DialogType.SELECT_PRODUCT_GROUP:
{
Data.SelectedIdType = ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups;
c_productGroupDiv.Attributes.CssStyle.Add("display", "block");
return c_productGroupsGrid.ClientID;
}
default:
{
Data.SelectedIdType = ReducePriceByAmountAction.Data.SelectionCriteria.Articles;
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.Clear();
Data.SelectedIDs.AddRange(selectedIDs.Distinct().ToList());
var hashtable = new Hashtable {{PROPERTY_ID, selectedIDs}};
SelectedItemIds = hashtable;
}
else
{
SelectedItemIds = null;
}
}
/// <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<ProductSet> ProductSetSorting(List<ProductSet> productSets, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
productSets.Sort((a, b) => a.GetDisplayName(FoundationContext.LanguageID).CompareTo(b.GetDisplayName(FoundationContext.LanguageID)));
break;
case ASSORTMENT_COLUMN:
productSets.Sort((a, b) => a.GetAssortment(FoundationContext.Token).DisplayName.
CompareTo(b.GetAssortment(FoundationContext.Token).DisplayName));
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) => a.DisplayName.CompareTo(b.DisplayName));
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<ProductGroup> ProductGroupSorting(List<ProductGroup> productGroups, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
productGroups.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName));
break;
case ASSORTMENT_COLUMN:
productGroups.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName));
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<Article> ArticleSorting(List<Article> articles, List<Litium.Studio.UI.Common.SortExpression> sortexpressions)
{
switch (sortexpressions[0].FieldName)
{
case DISPLAY_NAME_COLUMN:
articles.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName));
break;
case ARTICLE_NUMBER_COLUMN:
articles.Sort((a, b) => a.ArticleNumber.CompareTo(b.ArticleNumber));
break;
}
if (sortexpressions[0].SortDirection == SortDirection.Descending)
articles.Reverse();
return articles;
}
#endregion Private Metods
#region Protected Methods
protected override void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
InitializePageControls();
}
}
/// <summary>
/// Initializes the page controls.
/// </summary>
private void InitializePageControls()
{
InitializeRadioButtonListControl();
InitializeValidation();
InitializeGridsColumns();
InitializePopupWindowsDialog();
InitializeDescription();
}
/// <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<Article>();
if (Data.SelectedIDs.Count > 0)
{
foreach (Guid articleID in Data.SelectedIDs)
{
Article article;
if (Article.TryGet(articleID, out article, FoundationContext.Token))
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.ID, DisplayName = x.DisplayName, ArticleNumber = x.ArticleNumber }).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<ProductGroup>();
if (Data.SelectedIDs.Count > 0)
{
foreach (Guid groupID in Data.SelectedIDs)
{
ProductGroup productGroup;
if (ProductGroup.TryGet(groupID, out productGroup, FoundationContext.Token))
productGroups.Add(productGroup);
}
}
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 { x.ID, x.DisplayName, Assortment = x.Assortment.GetDisplayName(FoundationContext.LanguageID) }).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 groupID in Data.SelectedIDs)
{
Assortment assortment;
if (Assortment.TryGet(groupID, out assortment, FoundationContext.Token))
assortments.Add(assortment);
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
assortments = AssortmenSorting(assortments, sortexpressions);
return new PagedResult
{
Count = assortments.Count,
Reset = pagesize > startrowindex,
Data = assortments.Select(x => new { x.ID, x.DisplayName }).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<ProductSet>();
if (Data.SelectedIDs.Count > 0)
{
foreach (Guid groupID in Data.SelectedIDs)
{
ProductSet assortment;
if (ProductSet.TryGet(groupID, out assortment, FoundationContext.Token))
productSets.Add(assortment);
}
}
if (sortexpressions != null && sortexpressions.Count > 0)
productSets = ProductSetSorting(productSets, sortexpressions);
return new PagedResult
{
Count = productSets.Count,
Reset = pagesize > startrowindex,
Data = productSets.Select(x => new
{
x.ID,
DisplayName = x.GetDisplayName(FoundationContext.LanguageID),
Assortment = x.GetAssortment(FoundationContext.Token).DisplayName
}).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 == "Delete")
{
Guid deletableItemID = Guid.Empty;
switch (Data.SelectedIdType)
{
case ReducePriceByAmountAction.Data.SelectionCriteria.Assortments:
deletableItemID = (Guid) c_assortmentGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups:
deletableItemID = (Guid)c_productGroupsGrid.MasterTableView.DataKeyValues[e.Item.ItemIndex]["ID"];
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets:
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();
InitializeDescription();
SelectedItemIds = null;
}
protected void GridPageIndexChanged(object source, GridPageChangedEventArgs e)
{
c_hiddenFieldIDs.Value = string.Join(",", Data.SelectedIDs.ToList().ConvertAll(x => x.ToString()).ToArray());
}
[Serializable]
internal sealed class ReducePriceByPercentageResult
{
public Guid ID { get; set; }
public string DisplayName { get; set; }
public string ArticleNumber { get; set; }
}
#endregion Protected Methods
#region Implementation of IUIExtensionPanel
/// <summary>
/// Gets the panel data.
/// </summary>
/// <returns>Return an object with the panel data.</returns>
object IUIExtensionPanel.GetPanelData()
{
decimal amount;
Data.ApplyOnCampaignPriceCumulatively = c_applyOnCampaignCheckbox.Checked;
decimal.TryParse(c_textboxAmount.Text, out amount);
Data.DiscountAmountWithVAT = amount;
int maxDiscountsPerItemInOrder;
if (int.TryParse(c_textboxMaxDiscountsPerItemInOrder.Text, out maxDiscountsPerItemInOrder))
Data.MaxDiscountsPerItemInOrder = maxDiscountsPerItemInOrder;
else
Data.MaxDiscountsPerItemInOrder = -1;
return Data;
}
/// <summary>
/// Sets the panel data.
/// </summary>
/// <param name="data">The data.</param>
void IUIExtensionPanel.SetPanelData(object data)
{
if (data is ReducePriceByAmountAction.Data)
Data = (ReducePriceByAmountAction.Data)data;
InitializePageControls();
if (data is ReducePriceByAmountAction.Data)
{
c_applyOnCampaignCheckbox.Checked = Data.ApplyOnCampaignPriceCumulatively;
c_textboxAmount.Text = Data.DiscountAmountWithVAT.ToString();
c_textboxMaxDiscountsPerItemInOrder.Text = (Data.MaxDiscountsPerItemInOrder > 0) ? Data.MaxDiscountsPerItemInOrder.ToString() : string.Empty;
switch (Data.SelectedIdType)
{
case ReducePriceByAmountAction.Data.SelectionCriteria.Assortments:
c_assortmentGrid.Rebind();
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductGroups:
c_productGroupsGrid.Rebind();
break;
case ReducePriceByAmountAction.Data.SelectionCriteria.ProductSets:
c_productSetsGrid.Rebind();
break;
default:
c_articlesGrid.Rebind();
break;
}
}
}
#endregion
}
}
Translations
In order to add translations, a file named Administration.resx should be created under folder Site\Resources\ModuleECommerce\. The file should contain at least values to describe the name and the description of the custom action. The convention is:
- Action name: "${ActionClassName}Name"
- Action description: "${ActionClassName}Description"
So our custom action ReducePriceByAmountAction should have:
<data name="ReducePriceByAmountActionName">
<value>Reduce price by amount</value>
</data>
<data name="ReducePriceByAmountActionDescription">
<value>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quis purus lectus.</value>
</data>