Create a new Customer Entity in Sitecore Commerce 9.x

If you are looking to create a new customer entity in Sitecore Commerce 9.x, this is the post for you. I spent some time searching for code using my friend Google but couldn't find much. Hope this helps.

First, setup a new pipeline which accepts an object with values to create a new customer, make sure the output is of type Customer. This is crucial as we will pass the resulting customer to the persist block.


	namespace Plugin.YOURNAMESPACE.Pipelines
	{
		using Sitecore.Commerce.Core;
		using Sitecore.Framework.Pipelines;
		using Plugin.YOURNAMESPACE.Models;
		using Sitecore.Commerce.Plugin.Customers;
	
		[PipelineDisplayName("CreateCustomerMinionPipeline")]
		public interface ICreateCustomerMinionPipeline : IPipeline<SOMEOBJECTWITHCUSTOMERDATA, Customer, CommercePipelineExecutionContext>, IPipelineBlock<SOMEOBJECTWITHCUSTOMERDATA, Customer, CommercePipelineExecutionContext>, IPipelineBlock, IPipeline
		{
		}
	}
	namespace Plugin.YOURNAMESPACE.Pipelines
	{
		using Microsoft.Extensions.Logging;
		using Sitecore.Commerce.Core;
		using Sitecore.Framework.Pipelines;
		using Plugin.YOURNAMESPACE.Models;
		using Sitecore.Commerce.Plugin.Customers;
	
		public class CreateCustomerMinionPipeline: CommercePipeline<SOMEOBJECTWITHCUSTOMERDATA, Customer>, ICreateCustomerMinionPipeline, IPipeline<SOMEOBJECTWITHCUSTOMERDATA, Customer, CommercePipelineExecutionContext>, IPipelineBlock<SOMEOBJECTWITHCUSTOMERDATA, Customer, CommercePipelineExecutionContext>, IPipelineBlock, IPipeline
		{
			public CreateCustomerMinionPipeline(IPipelineConfiguration<ICreateCustomerMinionPipeline> configuration, ILoggerFactory loggerFactory) : base(configuration, loggerFactory)
			{
			}
		}
	}
								

Next, create a new block to create the customer entity.


	namespace Plugin.YOURNAMESPACE.Pipelines.Blocks
	{
		using Sitecore.Commerce.Core;
		using Sitecore.Framework.Pipelines;
		using System.Threading.Tasks;
		using Plugin.YOURNAMESPACE.Models;
		using Microsoft.Extensions.Logging;
		using System;
		using Sitecore.Commerce.Plugin.Customers;
		using Sitecore.Commerce.Plugin.ManagedLists;
		using System.Collections.Generic;
		using Sitecore.Commerce.EntityViews;
	
		[PipelineDisplayName("CreateCustomerMinionPipeline.CreateCustomerBlock")]
		public class CreateCustomersBlock : PipelineBlock<SOMEOBJECTWITHCUSTOMERDATA, Customer, CommercePipelineExecutionContext>
		{
			private readonly CommerceCommander _commerceCommander;
			private readonly FindEntityPipeline _findEntityPipeline;
			private readonly CreateCustomerPipeline _createCustomerPipeline;
			private readonly PersistEntityPipeline _persistEntityPipeline;
			public CreateCustomersBlock (CommerceCommander commerceCommander, FindEntityPipeline findEntityPipeline, CreateCustomerPipeline createCustomerPipeline, PersistEntityPipeline persistEntityPipeline)
			{
				_commerceCommander = commerceCommander;
				_findEntityPipeline = findEntityPipeline;
				_createCustomerPipeline = createCustomerPipeline;
				_persistEntityPipeline = persistEntityPipeline;
			}
			public override async Task<Customer> Run(SOMEOBJECTWITHCUSTOMERDATA arg, CommercePipelineExecutionContext context)
			{
				var propertiesPolicy = context.GetPolicy<CustomerPropertiesPolicy>();
				var customer = new Customer();
				string friendlyId = Guid.NewGuid().ToString("N");
	
				customer.AccountNumber = friendlyId;
				customer.FriendlyId = friendlyId;
				customer.Id = $"{CommerceEntity.IdPrefix<Customer>()}{friendlyId}";
	
				customer.Email = arg.CustomerEmail;
				customer.UserName = string.Concat("CommerceUsers\\", customer.Email);
				customer.AccountStatus = context.GetPolicy<KnownCustomersStatusesPolicy>()?.ActiveAccount;
	
				customer.FirstName = arg.CustomerFirstName;
				customer.LastName = arg.CustomerLastName;
	
				var details = new EntityView { Name = "Details" };
				details.Properties.Add(new ViewProperty { Name = propertiesPolicy.FirstName, RawValue = arg.CustomerFirstName });
				details.Properties.Add(new ViewProperty { Name = propertiesPolicy.LastName, RawValue = arg.CustomerLastName });
				details.Properties.Add(new ViewProperty { Name = propertiesPolicy.AccountNumber, RawValue = friendlyId });

				//Add to the customers index and the Customer lists, this will show up in the Biz Tools
				customer.SetComponent(new ListMembershipsComponent
				{
					Memberships = new List<string>
					{
						CommerceEntity.ListName<Customer>(),
						context.GetPolicy<KnownCustomersListsPolicy>().RecentCustomers,
						"CustomersIndex",
						"Customers"
					}
				});
				customer.GetComponent<CustomerDetailsComponent>()?.View.ChildViews.Add(details);
	
				string billingId = Guid.NewGuid().ToString("D");
				var billingAddressComponent = new AddressComponent { Name = "Billing" };
				billingAddressComponent.Id = billingId;
				billingAddressComponent.Party.FirstName = arg.CustomerFirstName;
				billingAddressComponent.Party.LastName = arg.CustomerLastName;

				billingAddressComponent.Party.State = arg.BillingInfo.BillingState;
				billingAddressComponent.Party.StateCode = arg.BillingInfo.BillingState;
				billingAddressComponent.Party.CountryCode = arg.BillingInfo.BillingCountry;
				billingAddressComponent.Party.Country = arg.BillingInfo.BillingCountry;

				billingAddressComponent.Party.City = arg.BillingInfo.BillingCity;
				billingAddressComponent.Party.Address1 = arg.BillingInfo.BillingAddress;
				billingAddressComponent.Party.ZipPostalCode = arg.BillingInfo.BillingZip;
				billingAddressComponent.Party.AddressName = "Billing";
				billingAddressComponent.Party.IsPrimary = true;

				//add address components to the customer
				customer.Components.Add(billingAddressComponent);
	
				string shippingId = Guid.NewGuid().ToString("D");
				var shippingAddressComponent = new AddressComponent { Name = "Shipping" };
				shippingAddressComponent.Id = shippingId;
	
				shippingAddressComponent.Party.FirstName = arg.CustomerFirstName;
				shippingAddressComponent.Party.LastName = arg.CustomerLastName;

				shippingAddressComponent.Party.State = arg.ShippingInfo.ShippingState;
				shippingAddressComponent.Party.StateCode = arg.ShippingInfo.ShippingState;
				shippingAddressComponent.Party.CountryCode = arg.ShippingInfo.ShippingCountry;
				shippingAddressComponent.Party.Country = arg.ShippingInfo.ShippingCountry;

				shippingAddressComponent.Party.City = arg.ShippingInfo.ShippingCity;
				shippingAddressComponent.Party.Address1 = arg.ShippingInfo.ShippingAddress;
				shippingAddressComponent.Party.ZipPostalCode = arg.ShippingInfo.ShippingZip;
				shippingAddressComponent.Party.AddressName = "Shipping";

				//add address components to the customer
				customer.Components.Add(shippingAddressComponent);
	
				//add customer to the entity index so that we can search later
				await this._persistEntityPipeline.Run(
				new PersistEntityArgument(
					new EntityIndex
					{
						Id = $"{EntityIndex.IndexPrefix<Customer>("Id")}{customer.Id}",
						IndexKey = customer.Id,
						EntityId = customer.Id
					}),
				context);
	
				return customer;
			}
		}
	}
										
								

Finally configure your pipeline in the ConfigureSitecore class.


	public void ConfigureServices(IServiceCollection services)
	{
		var assembly = Assembly.GetExecutingAssembly();
		services.RegisterAllPipelineBlocks(assembly);

		services.Sitecore().Pipelines(config => config
				.AddPipeline<ICreateCustomerMinionPipeline, CreateCustomerMinionPipeline>(configure =>
				{
					configure.Add<CreateCustomersBlock>().Add<PersistCustomerBlock>().Add<PersistCustomerIdIndexBlock>();
				})
			);
			//hopefully we create a new customer entity in the CreateCustomersBlock which is our code, followed by the PersistCustomerBlock and the PersistCustomerIdIndexBlock which will save our new customer.

		services.RegisterAllCommands(assembly);
	}

								

In the next blog post we will look at indexing custom attributes for entities so that we can search by custom attributes. Hopefully your code search brings you to this post and I hope this blog post helps in some way.

If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).