I am recently working on a commerce piece which has a requirement of extending existing order EntityView schema in Sitecore Commerce 9.3. Through this blog I hope to provide some information to Sitecore commerce developers who might work on similar tasks in future.
Approach:
1. Add a Component class to declare all the fields that need to be added to the order schema.
Example Code:
public class ExampleOrderComponent : Component
{
[Display(Name = "Example ID")]
public int ExampleID { get; set; } = 0;
[Display(Name = "Shipping Amount")]
public decimal ShippingAmount { get; set; } = 0.0m;
[Display(Name = "Express Amount")]
public decimal ExpressAmount { get; set; } = 0.0m;
}
2. Add a new view policy to declare view display properties.
Example Code:
public class ExampleOrderViewsPolicy : Policy
{
public string ExampleSettings { get; set; } ="ExampleSettings";
public string ExampleDisplayName { get; set; } = "Example Order"
}
3. Add a new constants class.
Example Code:
public static class ExampleSchemaConstants
{
public static class Pipelines
{
public static class Blocks
{
public const string GetExampleOrderViewBlock = "Example.orders.block.getexampleorderviewblock";
}
}
4. Add a new EntityView class to extend and populate the new schema.
Example Code:
namespace Plugin.ExampleProject.Schema.Orders.Pipelines.Blocks.EntityViews
{
[PipelineDisplayName(OrderSchemaConstants.Pipelines.Blocks.GetExampleOrderViewBlock)]
public class GetExampleOrderViewBlock : PipelineBlock<EntityView, EntityView, CommercePipelineExecutionContext>
{
private readonly ViewCommander _viewCommander;
public GetExampleOrderViewBlock(ViewCommander viewCommander)
{
this._viewCommander = viewCommander;
}
public override Task<EntityView> Run(EntityView entityView, CommercePipelineExecutionContext context)
{
Condition.Requires(entityView).IsNotNull($"{Name}: The argument cannot be null.");
var policy = context.GetPolicy<KnownOrderViewsPolicy>();
EntityViewArgument request = context.CommerceContext.GetObject<EntityViewArgument>();
if (string.IsNullOrEmpty(request?.ViewName) || !request.ViewName.Equals(policy.Master, StringComparison.OrdinalIgnoreCase))
{
return Task.FromResult(entityView);
}
// Only proceed if the current entity is an order
if (!(request.Entity is Order) || !string.IsNullOrEmpty(request.ForAction))
{
return Task.FromResult(entityView);
}
var order = request.Entity as Order;
var exampleOrderComponent = order.GetComponent<ExamplOrderComponent>();
var targetView = entityView;
if (request.ViewName == context.GetPolicy<KnownOrderViewsPolicy>().Master)
{
var view = new EntityView
{
Name = context.GetPolicy<ExampleOrderViewsPolicy>().ExampleSettings,
DisplayName = context.GetPolicy<ExampleOrderViewsPolicy>().ExampleDisplayName,
EntityId = entityView.EntityId,
ItemId = order.Id,
EntityVersion = entityView.EntityVersion
};
entityView.ChildViews.Add(view);
targetView = view;
// Invoke the method.
AddPropertiesToView(targetView, exampleOrderComponent);
}
return Task.FromResult(entityView);
}
/// <summary>
/// Extends the master view for orders.
/// </summary>
/// <param name="entityView"></param>
/// <param name="exampleOrderComponent"></param>
private void AddPropertiesToView(EntityView entityView, ExampleOrderComponent exampleOrderComponent)
{
foreach (PropertyInfo prop in exampleOrderComponent.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly))
{
entityView.Properties.Add(new ViewProperty()
{
Name = prop.Name,
RawValue = prop.GetValue(exampleOrderComponent),
IsReadOnly = true,
IsRequired = true,
DisplayName = exampleOrderComponent.GetDisplayName(prop.Name)
});
}
}
}
}
Below helper method is invoked in above code.
public static class AnnotationExtensionMethods
{
public static string GetDisplayName(this object instance, string propertyName)
{
var attrType = typeof(DisplayAttribute);
var property = instance.GetType().GetProperty(propertyName);
var displayAttributes = (DisplayAttribute)property.GetCustomAttributes(attrType, false).First();
if (displayAttributes == null)
return propertyName;
else
return displayAttributes.Name;
}
}
5. Lastly, Add the newly created block to IGetEntityViewPipeline
public void ConfigureServices(IServiceCollection services)
{
var assembly = Assembly.GetExecutingAssembly();
services.RegisterAllPipelineBlocks(assembly);
services.RegisterAllCommands(assembly);
services.Sitecore().Pipelines(config =>
config
.ConfigurePipeline<IGetEntityViewPipeline>(c =>
{
c.Add<GetExampleOrderViewBlock>()
.After<GetOrdersDashboardViewBlock>();
})
);
}
The coding journey with Sitecore Experience Commerce has been very interesting so far and I am really enjoying working on this platform. Happy Coding!!
Comments