Developing custom dialogs for the checkout process

Top  Previous  Next

Creating a custom checkout process step

 

1.Create new web user control (*.ascx) and place your own form controls into it.
2.Go to its code behind and set control class to inherit from CMS.EcommerceProvider.ShoppingCartStep.
3.There are several methods you can override to reach the required functionality:

- IsValid() – Validates current step custom data and returns validation result. True – all step data is correct and can be processed, False – some step data is not correct or missing and cannot be processed. In this case appropriate error message should be displayed. By default, it returns True.

- ProcessStep() – Processes current step information (updates shopping cart data) and returns result of this action. True – shopping cart data was updated successfully and customer can be moved to the next checkout process step, False – shopping cart update failed and customer cannot be moved to the next step. In this case appropriate error message should be displayed. By default, it returns True.

- ButtonBackClickAction() – Defines action which is run after the Back button is clicked. By default, the parent shopping cart control method ButtonBackClickAction() is called which moves customer one step backward in the checkout process.

- ButtonNextClickAction() – Defines action which is run after the “Next button” is clicked. By default, the parent shopping cart control method ButtonNextClickAction() is called  which moves customer one step forward in the checkout process when the current step data is valid and processed successfully.

4.There are several properties you should use to get or set required information:

       - ShoppingCartControl – parent shopping cart control the step belongs to

       - ShoppingCartInfoObj – shopping cart object which stores all data during the checkout process

       - CheckoutProcessStep – checkout process step information

5.The step control is created and can be registered as your custom checkout process step.

 

If the control represents checkout process steps in different checkout process types and these steps differ from each other only a little, you can create one control and specify a different behavior depending on the checkout process type as follows:

 

[C#]

 

switch (this.ShoppingCartControl.CheckoutProcessType)

{

   case CheckoutProcessEnum.LiveSite:

       // Here comes the code which will be run only

       // when it is a checkout process on the live site

       break;

 

   case CheckoutProcessEnum.CMSDeskOrder:

       // Here comes the code which will be run only

       // when it is a checkout process in the section CMSDesk/Tools/E-commerce/Orders

       break;

 

   default:

       // Here comes the code which will be run in all other cases

       break;

}

 

Example 1 - My step

 

The following example shows a simple checkout process step definition. It displays the total price and an editable field to insert a customer comment. After the Next button is clicked, the editable field is checked for emptiness. If it is not empty the customer comment is saved and shopping cart data is updated. Otherwise, an appropriate error message is displayed. If the customer is a member of role “VipCustomers”, an extra step with an additional form for VIP customers is loaded (MyVipStep.ascx). The Back button action is not overridden.

 

[MyStep.ascx]

 

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyStep.ascx.cs" Inherits="MyStep" %>

<asp:Label ID="lblError" runat="server" EnableViewState="false" Visible="false"></asp:Label>

<table>

   <tr>

       <td><asp:Label ID="lblTotalPrice" runat="server" /></td>

       <td><asp:Label ID="lblTotalPriceValue" runat="server" /></td>       

   </tr>

   <tr>

       <td><asp:Label ID="lblComment" runat="server" /></td>

       <td><asp:TextBox ID="txtComment" runat="server" TextMode="MultiLine" Rows="3" /></td>

   </tr>

</table>

 

 

[MyStep.ascx.cs]

 

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

 

using CMS.GlobalHelper;

using CMS.Ecommerce;

using CMS.EcommerceProvider;

 

public partial class MyStep : ShoppingCartStep

{

    protected void Page_Load(object sender, EventArgs e)

    {

        // Initialize labels

        lblTotalPrice.Text = ResHelper.GetString("MyStep.TotalPrice");

        lblComment.Text = ResHelper.GetString("MyStep.Comment");

 

        // Display rounded and formatted total price

        lblTotalPriceValue.Text = 

CurrencyInfoProvider.GetFormatedPrice(ShoppingCartInfoObj.RoundedTotalPrice, 

ShoppingCartInfoObj.CurrencyInfoObj);

 

        if (!this.ShoppingCartControl.IsCurrentStepPostBack)

        {

            // Load customer comment

            txtComment.Text = this.ShoppingCartInfoObj.ShoppingCartCustomData["CustomerComment"];

        }

 

 

    }

 

 

    /// <summary>

    /// Validates current step data.

    /// </summary>

    /// <returns></returns>

    public override bool IsValid()

    {

        // Check customer comment for emptiness

        if (txtComment.Text.Trim() == "")

        {

            // Display error message

            lblError.Text = ResHelper.GetString("MyStep.Error.CommentMissing");

            lblError.Visible = true;

 

            // Data are not correct - customer comment missing

            return false;

        }

        else

        {

            // Data are correct

            return true;

        }

    }

 

 

    /// <summary>

    /// Process current step data

    /// </summary>

    /// <returns></returns>

    public override bool ProcessStep()

    {

        // Update shopping cart with customer comment

        this.ShoppingCartInfoObj.ShoppingCartCustomData["CustomerComment"] = 

        txtComment.Text.Trim();

 

        try

        {

            // Update shopping cart in database

            ShoppingCartInfoProvider.SetShoppingCartInfo(this.ShoppingCartInfoObj);

 

            // Current step data were processed and saved succesfully

            return true;

        }

        catch

        {

            // Display error message

            lblError.Text = ResHelper.GetString("MyStep.Error.ShoppingCartUpdate");

            lblError.Visible = true;

 

            // Current step data update failed

            return false;

        }

    }

 

 

    /// <summary>

    /// Action after the "Next button" is clicked

    /// </summary>

    public override void ButtonNextClickAction()

    {

 

        // If customer is registered and is a member of role "VipCustomers"

        if ((this.ShoppingCartInfoObj.UserInfoObj != null)

            && (this.ShoppingCartInfoObj.UserInfoObj.IsInRole("VipCustomers",

 this.ShoppingCartInfoObj.SiteName)))

        {

            if (IsValid() && ProcessStep())

            {

                try

                {

                    // Load extra step for VIP customers which is not included 

     // in standard checkout process definition

                    ShoppingCartStep ctrl = 

(ShoppingCartStep)this.Page.LoadControl("~/CMSEcommerce/ShoppingCart/MyVipStep.ascx");

                    this.ShoppingCartControl.LoadStep(ctrl);

 

                    // Note: Current step index is not increased                                

                }

                catch

                {

                    // Error while loading extra step control -> Do standard action                    

                    base.ButtonNextClickAction();

                }

            }

        }

        else

        {

            // Do standard action (validate step data, process step data, load next step)

            base.ButtonNextClickAction();

        }

    }

 

}

 

 

My VIP step

 

This is an external checkout process step which is not included in standard checkout process definition. It is loaded only when the current customer is a member of role “VipCustomers”, however, you will need to use your own condition for loading your external steps. There is no data validation (Vip customer comment can be empty). Neither “Back button action” nor “Next button action” is overridden so it means the standard methods are called after the Back button and Next button are clicked.

 

 

[MyVipStep.ascx]

 

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyVipStep.ascx.cs" Inherits="MyVipStep" %>

<asp:Label ID="lblError" runat="server" EnableViewState="false" Visible="false"></asp:Label>

<asp:Label ID="lblComment" runat="server" />

<asp:TextBox ID="txtComment" runat="server" TextMode="MultiLine" Rows="3" />

 

 

[MyVipStep.ascx.cs]

 

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

 

using CMS.GlobalHelper;

using CMS.Ecommerce;

using CMS.EcommerceProvider;

 

public partial class CMSEcommerce_TestVipCustomers : ShoppingCartStep

{

    protected void Page_Load(object sender, EventArgs e)

    {

        // Initialize label

        lblComment.Text = ResHelper.GetString("MyVipStep.Comment");

 

        if (!this.ShoppingCartControl.IsCurrentStepPostBack)

        {

            // Load VIP customer extra comment

            txtComment.Text = 

Convert.ToString(this.ShoppingCartInfoObj.ShoppingCartCustomData["VipComment"]);

        }

 

 

    }  

 

    /// <summary>

    /// Process current step data

    /// </summary>

    /// <returns></returns>

    public override bool ProcessStep()

    {

        // Update shopping cart with VIP customer extra comment

        this.ShoppingCartInfoObj.ShoppingCartCustomData["VipComment"] = txtComment.Text.Trim();

 

        try

        {

            // Update shopping cart in database

            ShoppingCartInfoProvider.SetShoppingCartInfo(this.ShoppingCartInfoObj);

 

            // Current step data were processed and saved succesfully

            return true;

        }

        catch

        {

            // Display error message

            lblError.Text = ResHelper.GetString("MyStep.Error.ShoppingCartUpdate");

            lblError.Visible = true;

 

            // Current step data update failed

            return false;

        }

    }  

 

}

 

 

 

Important notes on step order

 

Notice that data of all steps (including Kentico CMS standard shopping cart steps) are always processed by themselves, not by the parent shopping cart control. It means if you reorder standard checkout process steps you can experience a strange behavior because of missing information or omitting some important action.

 

For example if you move step “Order preview” in the standard checkout process definition for the live site before steps “Select billing and shipping address” and “Select payment and shipping methods” some order preview data will be missing (billing and shipping addresses, payment method and shipping option) because they were not entered yet. But even worse is that entered data of the following two steps (“Select billing and shipping address”, “Select payment and shipping methods”) will not be saved.

 

This happens because the order is saved after the “Next button” of the step “Order preview” is clicked and these two steps include completely different actions after their “Next buttons” are clicked.