Monday, June 6, 2016

EpiServer for beginners: How to add custom fields to Order (eCommerce) programatically

Introduction

Some times ago, I had a post about adding a custom field to eCommerce from the user interface. That post got very popular and some folks like Khurram Khan and Steve C. mentioned that it is possible to add fields to eCommerce pragmatically. So in this post I will describe how to do it:

Steps
1- Create an initialization class

Create a class, inherit from IInitializableModule, add InitializableModule and ModuleDependency attribute to your class and you are almost there.

 [InitializableModule]

    [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]

    public class Initialization : IInitializableModule


* You will need to add "EPiServer.Commerce.Initialization" to have InitializationModule, "EPiServer.Framework" to have InitializableModuleAttribute and "Mediachase.MetaDataPlus.Configurator" to have MetaField methods but of course VS will add them for you when you write the names correctly


2-  Create the constructor and get the context
  public void Initialize(InitializationEngine context)

        {
        var mdContext = CatalogContext.MetaDataContext;

3- Use MetaField.Load to load your field from EPiServer.
        MetaField.Load(mdContext, name)


4- If the result was empty, create the field using MetaField.Create
The structure of the method is like this:

MetaField Create(MetaDataContext context, string metaNamespace, string name, string friendlyName, string description, MetaDataType dataType, int length, bool allowNulls, bool multiLanguageValue, bool allowSearch, bool isEncrypted);


* just to mention, length is the size of your data, so for example bool is 1, or DateTime is 8

5- Load the class that you want to add the field to it using  MetaClass.Load
  var mtClass = MetaClass.Load(mdContext, metaClassName);


6- Check if the meta field already exists in the meta class by checking its fields
  cls.MetaFields.Contains(field);


7- If the meta class doesn't have the class, add it using AddField
mtClass.AddField(field);


8- Smile :)

--------
It is very good idea to have simpler methods for adding fields and joining them to the meta class.

    private MetaField GetOrCreateMetaField(MetaDataContext mdContext, string metaDataNamespace, string name, MetaDataType type, int length, bool allowNulls, bool cultureSpecific)

        {

            var f = MetaField.Load(mdContext, name) ??

                    MetaField.Create(mdContext, metaDataNamespace, name, name, string.Empty, type, length, allowNulls, cultureSpecific, false, false);

            return f;

        }



        private void JoinField(MetaDataContext mdContext, MetaField field, string metaClassName)

        {

            var mtClass = MetaClass.Load(mdContext, metaClassName);



            if (MetaFieldIsNotConnected(field, mtClass ))

            {

                cls.AddField(field);

            }

        }



* And just to say: it is a good practice to have your strings inside enum classes. If you have a project, but you don't have any place for your enums and constants, you have to reconsider some of the stuff in your code :)

The whole code look like this:

 [InitializableModule]

    [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]

    public class Initialization : IInitializableModule

    {

  public void Initialize(InitializationEngine context)

        {



            MetaDataContext mdContext = CatalogContext.MetaDataContext;



            var myField = GetOrCreateMetaField(mdContext, Constants.Metadata.Namespace.Order,

          Extensions.PurchaseOrderExtensions.myFieldName, MetaDataType.DateTime, 8, true, false);

            JoinField(mdContext, myField, Constants.Metadata.OrderForm.ClassName);

        }



      private MetaField GetOrCreateMetaField(MetaDataContext mdContext, string metaDataNamespace, string name, MetaDataType type, int length, bool allowNulls, bool cultureSpecific)

        {

            var f = MetaField.Load(mdContext, name) ??

                    MetaField.Create(mdContext, metaDataNamespace, name, name, string.Empty, type, length, allowNulls, cultureSpecific, false, false);

            return f;

        }



        private void JoinField(MetaDataContext mdContext, MetaField field, string metaClassName)

        {

            var mtClass = MetaClass.Load(mdContext, metaClassName);



            if (MetaFieldIsNotConnected(field, mtClass ))

            {

                cls.AddField(field);

            }

        }



        private static bool MetaFieldIsNotConnected(MetaField field, MetaClass mtClass )

        {

            return mtClass != null && !cls.MetaFields.Contains(field);

        }

}

A Sample in a project
You can look at Steves  CommerceStarterKit and to be more specific, this page :) 

Acknowledgment
My gratitude to Steve Celius  for sharing his code with us.

4 comments:

  1. Thanks Raghu :)
    Happy to be helpful

    ReplyDelete
  2. Thank you for sharing excellent information. Your website is very cool. Fully useful your blog post... Women Online Fashion Store

    ReplyDelete
  3. salg kopi eksklusive klokker, der kombinerer elegant stil og avanceret teknologi, en række forskellige stilarter af salg accessoires kopi eksklusive klokker, går markøren mellem din eksklusive smagstil.

    ReplyDelete
  4. Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can't wait to read lots of your posts. magento 2 m2e

    ReplyDelete