Monday, January 30, 2017

Extending EPiServer Commerce Classes

In EPiServer we can extend the existing Commerce Classes. Such as PurchaseOrder, OrderForm and LineItem.

We can use this extended class to use meta class property as class property as oppose to calling object as indexer with hard coded property name.
for e.g


var orderForm = orderGroup.OrderForms[0]
var stockRoomId = orderForm["StockRoomId"]

/* We can use extended class to get value of stock room id */

var tcmsOrderForm = orderGroup.OrderForms[0] as TcmsOrderForm
var stockRoomId = tcmsOrderForm.StockRoomId;



First all of we need to define create the custom meta class and custom meta property in Commerce Section.

We will assign the associated meta property to meta classes.

We will have following custom classes

  • TcmsOrderForm
  • TcmsLineItem

We will also have following meta properties(Not all are included)

  • StockRoomId
  • PeriodId
  • UnitOfMeasure
  • IsPrescribed

Meta properties  will need to be assigned to associated Meta classes in Commerce section.
Once we have meta property and meta classes relation defined we are ready to create extended commerce classes.

Extended Purchase Order (TcmsPurchaseOrder)

using Mediachase.Commerce.Orders;
using System;
using System.Data;
using System.Linq;
using EPiServer7App.EPiServerCore.Utilities;

namespace EPiServer7App.Commerce.MetaFields.Orders
{
    /// <summary>
    /// Extended purchase order class which stores the date sent and date actioned
    /// </summary>
    [Serializable]
    public class TcmsPurchaseOrder : PurchaseOrder
    {
        public const string MetaClass_Name = "PurchaseOrder";

        public const string MetaField_DateActioned = "DateActioned";
        public const string MetaField_DateSent = "DateSent";
        public const string MetaField_OrderCreateLastStep = "OrderCreateLastStep";
        public const string MetaField_TrackingNumberIsFacilityGenerated = "TrackingNumberIsFacilityGenerated";

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsPurchaseOrder"/> class.
        /// </summary>
        public TcmsPurchaseOrder()
        {
            InitializeCustomFields();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsOrderForm"/> class.
        /// </summary>
        /// <param name="reader">The reader.</param>
        public TcmsPurchaseOrder(IDataReader reader)
            : base(reader)
        {
            InitializeCustomFields();
        }


        #endregion

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        protected void InitializeCustomFields()
        {
            DateActioned = null;
            DateSent = null;
            OrderCreateLastStep = Enums.OrderCreateStep.StockTake;
            TrackingNumberIsFacilityGenerated = false;
        }

        /// <summary>
        /// Gets or sets the date actioned.
        /// </summary>
        /// <value>
        /// The date actioned.
        /// </value>
        public DateTime? DateActioned
        {
            get { return this.GetDateTimeValue(MetaField_DateActioned, null); }
            set { this[MetaField_DateActioned] = value; }
        }


        /// <summary>
        /// Gets or sets the date sent.
        /// </summary>
        /// <value>
        /// The date sent.
        /// </value>
        public DateTime? DateSent
        {
            get { return this.GetDateTimeValue(MetaField_DateSent, null); }
            set { this[MetaField_DateSent] = value; }
        }

        /// <summary>
        /// Gets or sets the order create last step.
        /// </summary>
        /// <value>
        /// The order create last step.
        /// </value>
        public Enums.OrderCreateStep OrderCreateLastStep
        {
            get { return (Enums.OrderCreateStep) this.GetIntWithDefaultValue(MetaField_OrderCreateLastStep, (int) Enums.OrderCreateStep.StockTake); }
            set { this[MetaField_OrderCreateLastStep] = (int) value; }
        }

        public bool IsEditable
        {
            get
            {
                var nonEditableStatus = new[]
                {
                    Enums.TcmsOrderStatus.Completed,
                    Enums.TcmsOrderStatus.SubmittedToDistributor,
                    Enums.TcmsOrderStatus.Cancelled
                };

                return !nonEditableStatus.Contains(EnumHelper.ParseOrDefault<Enums.TcmsOrderStatus>(Status));
            }
        }

        /// <summary>
        /// Gets or sets if the tracking number (purchase order number) has been set by the facility as
        /// opposite of being system generated.
        /// </summary>
        public bool TrackingNumberIsFacilityGenerated
        {
            get { return ((bool?) this[MetaField_TrackingNumberIsFacilityGenerated]).GetValueOrDefault(false);}
            set { this[MetaField_TrackingNumberIsFacilityGenerated] = value; }
        }
    }
}

Extended Order Form (TcmsOrderForm)

using System;
using System.Data;
using System.Linq;
using System.Runtime.Serialization;
using EPiServer7App.EPiServerCore.Utilities;
using Mediachase.Commerce.Orders;
using Mediachase.Commerce.Storage;

namespace EPiServer7App.Commerce.MetaFields.Orders
{
    /// <summary>
    /// Extended version of the OrderForm
    /// </summary>
    [Serializable]
    public class TcmsOrderForm : OrderForm
    {
        public const string MetaClass_Name = "OrderFormEx";

        public const string MetaField_StockRoomId = "StockRoomId";
        public const string MetaField_PeriodId = "PeriodId";
        public const string MetaField_Comments = "Comments";

        #region Constructors
        public TcmsOrderForm()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsOrderForm"/> class.
        /// </summary>
        /// <param name="reader">The reader.</param>
        public TcmsOrderForm(IDataReader reader)
            : base(reader)
        {
            InitializeCustomFields();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsOrderForm"/> class.
        /// </summary>
        /// <param name="info">The information.</param>
        /// <param name="context">The context.</param>
        protected TcmsOrderForm(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            InitializeCustomFields();
        } 
        #endregion

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        protected void InitializeCustomFields()
        {
            StockRoomId = Guid.Empty;
            PeriodId = Guid.Empty;
        }

        /// <summary>
        /// Gets or sets the stock room identifier.
        /// </summary>
        /// <value>
        /// The stock room identifier.
        /// </value>
        public Guid StockRoomId
        {
            get { return this.GetGuidValue(MetaField_StockRoomId, Guid.Empty).Value; }
            set { this[MetaField_StockRoomId] = value; }
        }


        /// <summary>
        /// Gets or sets the period identifier.
        /// </summary>
        /// <value>
        /// The period identifier.
        /// </value>
        public Guid PeriodId
        {
            get { return this.GetGuidValue(MetaField_PeriodId, Guid.Empty).Value; }
            set { this[MetaField_PeriodId] = Convert.ToString(value); }
        }

        /// <summary>
        /// Gets or sets the comments.
        /// </summary>
        /// <value>
        /// The comments.
        /// </value>
        public string Comments
        {
            get { return GetString(MetaField_Comments); }
            set { this[MetaField_Comments] = value; }
        }

        protected override void PopulateCollections(DataTableCollection tables, string filter)
        {
            filter = string.Format("OrderFormId = '{0}'", OrderFormId);
            base.PopulateCollections(tables, filter);            
        }

    }
}

Extended Line Item (TcmsLineItem)

using System;
using System.Runtime.Serialization;
using Mediachase.Commerce.Orders;

namespace EPiServer7App.Commerce.MetaFields.Orders
{
    /// <summary>
    /// Extended class for LineItem with TCMS specific values
    /// </summary>
    public class TcmsLineItem : LineItem
    {
        public const string MetaClass_Name = "LineItemEx";

        public const string MetaField_UnitOfMeasure = "UnitOfMeasure";
        public const string MetaField_ActualCatalogEntryId = "ActualCatalogEntryId";
        public const string MetaField_IsPrescribed = "IsPrescribed";
        
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsLineItem"/> class.
        /// </summary>
        public TcmsLineItem()
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TcmsLineItem"/> class.
        /// </summary>
        /// <param name="info">The information.</param>
        /// <param name="context">The context.</param>
        protected TcmsLineItem(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            Initialize();
        } 
        #endregion

        /// <summary>
        /// Initializes this instance with default values
        /// </summary>
        /// <remarks>The base class doesn't expose this as virtual. Sigh!</remarks>
        protected virtual void Initialize()
        {
            UnitOfMeasure = Enums.UnitOfMeasure.Carton;
            IsPrescribed = false;
        }

        /// <summary>
        /// Gets or sets the unit of measure.
        /// </summary>
        /// <value>
        /// The unit of measure.
        /// </value>
        public Enums.UnitOfMeasure UnitOfMeasure
        {
            get { return (Enums.UnitOfMeasure)GetInt(MetaField_UnitOfMeasure); }
            set { this[MetaField_UnitOfMeasure] = (int)value; }
        }
     
        /// <summary>
        /// Gets or sets a value indicating whether [is prescribed].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [is prescribed]; otherwise, <c>false</c>.
        /// </value>
        public bool IsPrescribed
        {
            get { return GetBool(MetaField_IsPrescribed); }
            set { this[MetaField_IsPrescribed] = value; }
        }      
    }
}



ecf.order.config

We also need to update the ecf.order.config section to include the custom class definition

<?xml version="1.0"?>
<Orders newOrderStatus="Draft" autoConfigure="true" shipmentAutoReleaseTimeout="1:0:0">
  <MappedTypes>
    <ShoppingCartType name="Mediachase.Commerce.Orders.Cart,Mediachase.Commerce" />
    
    <!-- Custom Lines -->
    <PurchaseOrderType name="EPiServer7App.Commerce.MetaFields.Orders.TcmsPurchaseOrder,EPiServer7App.Commerce" />
    <OrderFormType name="EPiServer7App.Commerce.MetaFields.Orders.TcmsOrderForm,EPiServer7App.Commerce" />
    <LineItemType name="EPiServer7App.Commerce.MetaFields.Orders.TcmsLineItem,EPiServer7App.Commerce" />    
    <!-- END Custom Lines-->
    
    <!-- ORIGINAL LINES -->
    
    <!--
    <PurchaseOrderType name="Mediachase.Commerce.Orders.PurchaseOrder,Mediachase.Commerce" />
    <OrderFormType name="Mediachase.Commerce.Orders.OrderForm,Mediachase.Commerce" />
    <LineItemType name="Mediachase.Commerce.Orders.LineItem,Mediachase.Commerce" />
    -->

    <PaymentPlanType name="Mediachase.Commerce.Orders.PaymentPlan,Mediachase.Commerce" />    
    <OrderGroupAddressType name="Mediachase.Commerce.Orders.OrderAddress,Mediachase.Commerce" />
    <ShipmentType name="Mediachase.Commerce.Orders.Shipment,Mediachase.Commerce" />
    <OrderSearchType name=" Mediachase.Commerce.Orders.Search.OrderSearch,Mediachase.Commerce" />
  </MappedTypes>
  <MetaClasses>
    <PurchaseOrderClass name="PurchaseOrder" />
    <PaymentPlanClass name="PaymentPlan" />
    <ShoppingCartClass name="ShoppingCart" />]
    <OrderFormClass name="OrderFormEx" />
    <LineItemClass name="LineItemEx" />    
    <ShipmentClass name="ShipmentEx" />
    <OrderAddressClass name="OrderGroupAddressEx" />
  </MetaClasses>
  <Connections confConnectionStringName="EcfSqlConnection" transConnectionStringName="EcfSqlConnection" />
  <Cache enabled="true" shippingCollectionTimeout="0:0:10" paymentCollectionTimeout="0:0:10" statusCollectionTimeout="0:0:10" countryCollectionTimeout="0:0:10" taxCollectionTimeout="0:0:10" jurisdictionCollectionTimeout="0:0:10" />
  <Roles>
    <add name="OrderSupervisorRole" value="Order Supervisor" />
    <add name="OrderManagerRole" value="Order Manager" />
    <add name="ShippingManagerRole" value="Shipping Manager" />
    <add name="ReceivingManagerRole" value="Receiving Manager" />
  </Roles>
</Orders>

After defining custom classes and configuration we are now ready to use the classes
Below are the utility functions and example to use the above classes.


var purchaseOrder = new TcmsPurchaseOrder { TrackingNumber = "DummyTrackingNumber" };

var orderForm = purchaseOrder.OrderForms.AddNew() as TcmsOrderForm;
    
orderForm.LineItems.Add(new TcmsLineItem()
  {
       Quantity = 1,
       ActualCatalogEntryId = 24,
       ExtendedPrice = (decimal)20.30,
       IsPrescribed = true,
       UnitOfMeasure = Enums.UnitOfMeasure.Carton,
       StockTakeQuantityInPieces = 12,
  });
     
     
  //Assumes that we're only using one form!
  return orderGroup.OrderForms[0] as TcmsOrderForm;

Extension method to convert normal classes to extended classes

using System.Collections.Generic;
using EPiServer7App.Commerce.MetaFields.Orders;
using Mediachase.Commerce.Orders;

namespace EPiServer7App.Commerce.Services.Extensions
{
    /// <summary>
    /// Creates extension methods for order group implementations such as Cart and Purchase Order
    /// </summary>
    public static class OrderGroupExtensions
    {
        /// <summary>
        /// Gets the TCMS order form.
        /// </summary>
        /// <param name="orderGroup">The order group.</param>
        /// <returns></returns>
        public static TcmsOrderForm GetTcmsOrderForm(this OrderGroup orderGroup)
        {
            if (orderGroup == null)
                return null;

            if (orderGroup.OrderForms.Count < 1)
                return null;

            //Assumes that we're only using one form!
            return orderGroup.OrderForms[0] as TcmsOrderForm;
        }

        /// <summary>
        /// To the TCMS order form.
        /// </summary>
        /// <param name="orderForm">The order form.</param>
        /// <returns></returns>
        public static TcmsOrderForm ToTcmsOrderForm(this OrderForm orderForm)
        {
            if (orderForm == null)
                return null;

            return orderForm as TcmsOrderForm;
        }

        /// <summary>
        /// To the TCMS line item.
        /// </summary>
        /// <param name="lineItem">The line item.</param>
        /// <returns></returns>
        public static TcmsLineItem ToTcmsLineItem(this LineItem lineItem)
        {
            if (lineItem == null)
                return null;

            return lineItem as TcmsLineItem;
        }
    }
}



No comments:

Post a Comment