Introduction

In part 1 of this series, we highlighted the areas of the Sitecore Commerce engine which can be modified to enable the passing of orders and customers to an ERP system. If you completed the steps in the first article you should now have code “mocking” calls to an ERP. There is, however, nowhere in the system for back-office users to view the fields containing integration status of business entities.

For example, we added a field called “Is integrated” to our “Order” business entity but how will the end user know that the process succeeded without calling the API or searching for the order in the destination ERP system?

The following article will outline the process of modifying the entity views to show the custom fields that were added to the order and customer entities via components in part.

The final result will look something like this…modified view

The example is made up of the following artifacts:-

  1. A new pipeline block extending the functionality of the “GetEntityView” pipeline.
  2. A new pipeline registration

Modifying the entity views to display the integration fields in the business tools

We are going to modify the standard process within the system to do the following:-

  1. A user opens the “Customer and Order Manager” section from within Sitecore, selects the “Orders” tab, then selects an order from the list (Unchanged)
  2. A call is made to the Sitecore Commerce API for the views relating to the “Order” entity. (Unchanged)
  3. The “GetEntityView” pipeline is fired (Unchanged)
  4. The relevant view for the “Order” entity is modified in the pipeline and passed back through to the UI.
  5. The same process is followed for the “Customer” entity

Open the SDK example solution

  1. Open the project named “Sitecore.Commerce.Connectors.MYERP.Plugin” that was created in part 1.
  2. Under “Pipelines\Blocks” add a new class named “ModifyViewsBlock.cs”
  3. Copy the code below into the class and cleanup as necessary


namespace Sitecore.Commerce.Connectors.MYERP.Plugin.Pipelines.Blocks
{
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Sitecore.Commerce.Connectors.MYERP.Plugin.Components;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.EntityViews;
using Sitecore.Commerce.Plugin.Customers;
using Sitecore.Commerce.Plugin.Orders;
using Sitecore.Framework.Conditions;
using Sitecore.Framework.Pipelines;
/// <summary>
/// The process orders minion block.
/// </summary>
public class ModifyViewsBlock : PipelineBlock<EntityView, EntityView, CommercePipelineExecutionContext>
{
/// <summary>
/// The _pipeline.
/// </summary>
private readonly IPersistEntityPipeline _pipeline;
/// <summary>
/// Initializes a new instance of the <see cref="ModifyViewsBlock"/> class.
/// </summary>
/// <param name="persistEntityPipeline">
/// The persist entity pipeline.
/// </param>
public ModifyViewsBlock(IPersistEntityPipeline persistEntityPipeline)
{
this._pipeline = persistEntityPipeline;
}
/// <summary>
/// The run.
/// </summary>
/// <param name="entityView">
/// The entity view.
/// </param>
/// <param name="context">
/// The context.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task<EntityView> Run(EntityView entityView, CommercePipelineExecutionContext context)
{
Condition.Requires(entityView).IsNotNull("The argument can not be null");
var argument = context.CommerceContext.GetObjects<EntityViewArgument>().FirstOrDefault();
if (argument == null)
{
return Task.FromResult(entityView);
}
if (argument.ViewName != context.GetPolicy<KnownOrderViewsPolicy>().Summary &&
argument.ViewName != context.GetPolicy<KnownOrderViewsPolicy>().Master &&
argument.ViewName != context.GetPolicy<KnownOrderViewsPolicy>().Preview &&
argument.ViewName != context.GetPolicy<KnownCustomerViewsPolicy>().Preview &&
argument.ViewName != context.GetPolicy<KnownCustomerViewsPolicy>().Master)
{
// Do nothing if this request is for a different view
return Task.FromResult(entityView);
}
if (argument.Entity == null)
{
// Do nothing if there is no entity loaded
return Task.FromResult(entityView);
}
// Only do something if the Entity is an order or customer
if (!(argument.Entity is Order) && !(argument.Entity is Customer))
{
return Task.FromResult(entityView);
}
EntityView entityViewToProcess;
if (argument.ViewName == context.GetPolicy<KnownOrderViewsPolicy>().Master && argument.Entity is Order)
{
entityViewToProcess = entityView.ChildViews.FirstOrDefault(p => p.Name == "Summary") as EntityView;
}
else if (argument.ViewName == context.GetPolicy<KnownCustomerViewsPolicy>().Master && argument.Entity is Customer)
{
entityViewToProcess = entityView.ChildViews.FirstOrDefault(p => p.Name == "Details") as EntityView;
}
else
{
entityViewToProcess = entityView;
}
if (entityViewToProcess == null)
{
return Task.FromResult(entityView);
}
// Orders
if ((argument.ViewName == context.GetPolicy<KnownOrderViewsPolicy>().Master
|| argument.ViewName == context.GetPolicy<KnownOrderViewsPolicy>().Summary) && argument.Entity is Order)
{
OrderSummaryAndDetail(entityViewToProcess, (Order)argument.Entity);
}
else if (argument.ViewName == context.GetPolicy<KnownOrderViewsPolicy>().Summary && argument.Entity is Order)
{
OrderPreview(entityViewToProcess, (Order)argument.Entity);
}
// Customers
else if (argument.ViewName == context.GetPolicy<KnownCustomerViewsPolicy>().Preview && argument.Entity is Customer)
{
CustomerPreview(entityViewToProcess, (Customer)argument.Entity);
}
else if (argument.ViewName == context.GetPolicy<KnownCustomerViewsPolicy>().Master && argument.Entity is Customer)
{
CustomerSummaryAndDetail(entityViewToProcess, (Customer)argument.Entity);
}
return Task.FromResult(entityView);
}
/// <summary>
/// The order preview.
/// </summary>
/// <param name="entityViewToProcess">
/// The entity view to process.
/// </param>
/// <param name="order">
/// The order.
/// </param>
private static void OrderPreview(EntityView entityViewToProcess, Order order)
{
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP order no.",
DisplayName = "ERP order no.",
IsReadOnly = true,
RawValue = order.GetComponent<ErpOrderStatusComponent>().ErpOrderNumber,
Value = order.GetComponent<ErpOrderStatusComponent>().ErpOrderNumber
});
}
/// <summary>
/// The customer preview.
/// </summary>
/// <param name="entityViewToProcess">
/// The entity view to process.
/// </param>
/// <param name="customer">
/// The customer.
/// </param>
private static void CustomerPreview(EntityView entityViewToProcess, Customer customer)
{
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP customer no.",
DisplayName = "ERP customer no.",
IsReadOnly = true,
RawValue = customer.GetComponent<ErpCustomerStatusComponent>().ErpCustomerNo,
Value = customer.GetComponent<ErpCustomerStatusComponent>().ErpCustomerNo
});
}
/// <summary>
/// The order summary and detail.
/// </summary>
/// <param name="entityViewToProcess">
/// The entity view to process.
/// </param>
/// <param name="order">
/// The order.
/// </param>
private static void OrderSummaryAndDetail(EntityView entityViewToProcess, Order order)
{
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP order no.",
DisplayName = "ERP order no.",
IsReadOnly = true,
RawValue = order.GetComponent<ErpOrderStatusComponent>().ErpOrderNumber,
Value = order.GetComponent<ErpOrderStatusComponent>().ErpOrderNumber
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP status date",
DisplayName = "ERP status date",
IsReadOnly = true,
RawValue = order.GetComponent<ErpOrderStatusComponent>().StatusDate,
Value =
order.GetComponent<ErpOrderStatusComponent>()
.StatusDate.ToString(CultureInfo.InvariantCulture)
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "Is integrated",
DisplayName = "Is integrated",
IsReadOnly = true,
RawValue = order.GetComponent<ErpOrderStatusComponent>().Integrated,
Value = order.GetComponent<ErpOrderStatusComponent>().Integrated.ToString()
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP status message",
DisplayName = "ERP status message",
IsReadOnly = true,
RawValue = order.GetComponent<ErpOrderStatusComponent>().StatusMessage,
Value = order.GetComponent<ErpOrderStatusComponent>().StatusMessage
});
}
/// <summary>
/// The customer summary and detail.
/// </summary>
/// <param name="entityViewToProcess">
/// The entity view to process.
/// </param>
/// <param name="customer">
/// The customer.
/// </param>
private static void CustomerSummaryAndDetail(EntityView entityViewToProcess, Customer customer)
{
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP customer no.",
DisplayName = "ERP customer no.",
IsReadOnly = true,
RawValue = customer.GetComponent<ErpCustomerStatusComponent>().ErpCustomerNo,
Value = customer.GetComponent<ErpCustomerStatusComponent>().ErpCustomerNo
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP status date",
DisplayName = "ERP status date",
IsReadOnly = true,
RawValue = customer.GetComponent<ErpCustomerStatusComponent>().StatusDate,
Value =
customer.GetComponent<ErpCustomerStatusComponent>()
.StatusDate.ToString(CultureInfo.InvariantCulture)
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "Is integrated",
DisplayName = "Is integrated",
IsReadOnly = true,
RawValue = customer.GetComponent<ErpCustomerStatusComponent>().Integrated,
Value = customer.GetComponent<ErpCustomerStatusComponent>().Integrated.ToString()
});
entityViewToProcess.Properties.Add(
new ViewProperty
{
Name = "ERP status message",
DisplayName = "ERP status message",
IsReadOnly = true,
RawValue = customer.GetComponent<ErpCustomerStatusComponent>().StatusMessage,
Value = customer.GetComponent<ErpCustomerStatusComponent>().StatusMessage
});
}
}
}

The code above is called for every request for every entity view but the “if” statements at the top of the block ensure that the code is run at the correct time. After the block validates that is should run correctly, the entity within the call is retrieved and the custom fields are pulled from the plugin components and returned in the view

Registering the new block against the pipeline

  1. Open the class named “ConfigureSitecore.cs” at the root of your project
  2. Add the following code to the “ConfigureServices” method…


services.Sitecore()
.Pipelines(
pipeLineConfig =>
pipeLineConfig.ConfigurePipeline<IGetEntityViewPipeline>(
config => config.Add<ModifyViewsBlock>()));

The full class should now look like this…


namespace Sitecore.Commerce.Connectors.MYERP.Plugin
{
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Sitecore.Commerce.Connectors.MYERP.Plugin.Pipelines.Blocks;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.EntityViews;
using Sitecore.Commerce.Plugin.Orders;
using Sitecore.Framework.Configuration;
using Sitecore.Framework.Pipelines.Definitions.Extensions;
/// <summary>
/// The configure site core.
/// </summary>
public class ConfigureSitecore : IConfigureSitecore
{
/// <summary>
/// The configure services.
/// </summary>
/// <param name="services">
/// The services.
/// </param>
public void ConfigureServices(IServiceCollection services)
{
var assembly = Assembly.GetExecutingAssembly();
services.RegisterAllPipelineBlocks(assembly);
services.Sitecore()
.Pipelines(
pipeLineConfig =>
pipeLineConfig.ConfigurePipeline<IReleasedOrdersMinionPipeline>(
config => config.Add<SendOrderToErpMinionBlock>()
.After<MoveReleasedOrderBlock>()));
services.Sitecore()
.Pipelines(
pipeLineConfig =>
pipeLineConfig.ConfigurePipeline<IGetEntityViewPipeline>(
config => config.Add<ModifyViewsBlock>()));
services.RegisterAllCommands(assembly);
}
}
}

Running and debugging the example

Verify your solution, should look like this…

 example solution - part 2

Testing

To test that your code is working

  1. Ensure that you have followed the steps in part 1.
  2. Start IIS Express by starting the demo solution
  3. Go to Sitecore and select “Customers and orders manager” from the launchpad
  4. Select the “Orders” tab
  5. Select an order from the list that has been processed by the “ReleasedOrdersMinion” (refer to part 1).
  6. If you have breakpoint added to the new pipeline code it should be hit now.
  7. The Preview section on the right should contain your custom fields. If you view the details of the order, the other custom fields will be shown.
  8. Debug the new pipeline block to see how it works.
  9. Repeat these steps for customers

customer preview

Conclusion

In other posts, I plan to show the following.

  1. New API functionality to resend orders to the ERP.