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…
The example is made up of the following artifacts:-
- A new pipeline block extending the functionality of the “GetEntityView” pipeline.
- 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:-
- A user opens the “Customer and Order Manager” section from within Sitecore, selects the “Orders” tab, then selects an order from the list (Unchanged)
- A call is made to the Sitecore Commerce API for the views relating to the “Order” entity. (Unchanged)
- The “GetEntityView” pipeline is fired (Unchanged)
- The relevant view for the “Order” entity is modified in the pipeline and passed back through to the UI.
- The same process is followed for the “Customer” entity
Open the SDK example solution
- Open the project named “Sitecore.Commerce.Connectors.MYERP.Plugin” that was created in part 1.
- Under “Pipelines\Blocks” add a new class named “ModifyViewsBlock.cs”
- Copy the code below into the class and cleanup as necessary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
- Open the class named “ConfigureSitecore.cs” at the root of your project
- Add the following code to the “ConfigureServices” method…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services.Sitecore() | |
.Pipelines( | |
pipeLineConfig => | |
pipeLineConfig.ConfigurePipeline<IGetEntityViewPipeline>( | |
config => config.Add<ModifyViewsBlock>())); |
The full class should now look like this…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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…
Testing
To test that your code is working
- Ensure that you have followed the steps in part 1.
- Start IIS Express by starting the demo solution
- Go to Sitecore and select “Customers and orders manager” from the launchpad
- Select the “Orders” tab
- Select an order from the list that has been processed by the “ReleasedOrdersMinion” (refer to part 1).
- If you have breakpoint added to the new pipeline code it should be hit now.
- 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.
- Debug the new pipeline block to see how it works.
- Repeat these steps for customers
Conclusion
In other posts, I plan to show the following.
- New API functionality to resend orders to the ERP.