Elements of a Commerce Engine plugin
The Commerce Core infrastructure defines the various core classes that compose a Commerce plugin.
This topic introduces some of the key objects classes that Commerce micro-service plugins commonly contribute (the Commerce Core overview topic provides a more comprehensive list of Commerce core objects and concepts).
When you install the Visual Studio extension packaged as part of the Commerce.Engine.SDK, the Sitecore.Commerce.Plugin.Sample
project template provides samples for most of these common classes.
Entities
Commerce plugins can contribute entities. Commerce entities are based on a core CommerceEntity
class, and are designed to directly represent key business concepts inherent to e-commerce. For example, the Sitecore.Commerce.Plugin.Orders
plugin contributes the Orders
entity and the SalesActivity
entity; the Sitecore.Commerce.Plugin.Carts
plugin contributes the carts
entity, and so on.
An entity class is stored as a single unit in a persistent storage. There is no need to manage any database schema to store your custom defined entity.
A commerce entity has a unique identifier that you use to retrieve it using the Service API.
Components
The Commerce Core defines a component class which is a basic structure that enables compositional extensibility . Commerce plugins can contribute components as a way to extend commerce entities. For example, the availability plugin Sitecore.Commerce.Plugin.Availability
contributes the itemAvailabilityComponent
that extends the SellableItem
entity, which is part of the Sitecore.Commerce.Plugin.Catalog
. You typically associate a component to an entity by hooking into a pipeline.
The following shows an example of the itemAvailabilityComponent
:
namespace Sitecore.Commerce.Plugin.Availability
{
using System;
using Sitecore.Commerce.Core;
/// <summary>
/// The item availability component.
/// </summary>
public class ItemAvailabilityComponent : Component
{
/// <summary>
/// Gets or sets the item identifier.
/// </summary>
/// <value>
/// The item identifier.
/// </value>
public string ItemId { get; set; }
/// <summary>
/// Gets or sets the available quantity.
/// </summary>
/// <value>
/// The available quantity.
/// </value>
public decimal AvailableQuantity { get; set; }
/// <summary>
/// Gets or sets the available date.
/// </summary>
/// <value>
/// The available date.
/// </value>
public DateTimeOffset AvailableDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is available.
/// </summary>
/// <value>
/// <c>true</c> if this instance is available; otherwise, <c>false</c>.
/// </value>
public bool IsAvailable { get; set; }
/// <summary>
/// Gets or sets the availability expires.
/// </summary>
/// <value>
/// The availability expires.
/// </value>
public DateTimeOffset AvailabilityExpires { get; set; }
}
}
Models
Commerce plugins can contribute models, which are POCO classes that are reusable inside entities and components. You can use models to form and present data that is returned as part of a command response or API request response.
The following shows an example of the CreateOrder
model class:
namespace Sitecore.Commerce.Plugin.Orders
{ using Sitecore.Commerce.Core;
/// <summary>
/// Defines the created order model.
/// </summary>
/// <seealso cref="Sitecore.Commerce.Core.Model" />
public class CreatedOrder : Model
{
/// <summary>
/// Initializes a new instance of the <see cref="CreatedOrder"/> class.
/// </summary>
public CreatedOrder()
{
this.OrderId = string.Empty;
}
/// <summary>
/// Gets or sets the order identifier.
/// </summary>
/// <value>
/// The order identifier.
/// </value>
public string OrderId { get; set; }
}
}
Controllers
Controllers expose Commerce functionality implemented as commands in plugins. For example, if you define a custom command, and you want to expose this command through a REST API, you must define a custom controller action. Controller classes are ODATA-compliant and based on a standard ASP.NET Core model-view-controller (MVC) pattern.
Commands
Plugins define commands, which act like the outward facing API of Sitecore XC. A command class defines and encapsulates all information required to perform an action or trigger an event when invoked.
Commands can also trigger actions internally, within the Commerce Engine, to run other pipelines or to take other actions. For example, a call to get a sellable item using a controller could invoke the GetSellableItemCommand
, which then runs the GetSellableItem
pipeline.
Pipelines
The Commerce Core defines a pipeline framework that supports extensibility. In a Commerce plugin, pipelines act as containers for business logic. The pipeline class itself is typically lightweight and mainly expresses the definition of the pipeline itself. For example, the following shows the ICreateOrderPipeline
class, as defined by the Orders plugin:
namespace Sitecore.Commerce.Plugin.Orders
{
using Sitecore.Commerce.Core;
using Sitecore.Framework.Pipelines;
/// <summary>
/// Defines the create order pipeline.
/// </summary>
[PipelineDisplayName(OrdersConstants.Pipelines.CreateOrder)]
public interface ICreateOrderPipeline :IPipeline<CartEmailArgument, Order, CommercePipelineExecutionContext>
{
}
}
Commerce pipelines are composed of blocks. Pipeline blocks are responsible for implementing behaviors, actions and business logic.
You use code to work and extend Commerce Engine pipelines and blocks to meet your specific commerce solution requirements.
Following is an example of the Commerce pipeline block OrderPlacedAssignConfirmationIdBlock
, which is responsible to generate the unique ID that is assigned to the order when it is placed.
namespace Sitecore.Commerce.Plugin.Orders
{
using System.Threading.Tasks;
using Sitecore.Commerce.Core;
using Sitecore.Framework.Conditions;
using Sitecore.Framework.Pipelines;
using System.Linq;
using Core.Commands;
using System;
using Microsoft.Extensions.Logging;
/// </summary>
public OrderPlacedAssignConfirmationIdBlock(GenerateUniqueCodeCommand generateUniqueCodeCommand;
{
_generateUniqueCodeCommand = generateUniqueCodeCommand;
}
public async override Task<Order> Run(Order order, CommercePipelineExecutionContext context)
{
Condition.Requires(order).IsNotNull("The order can not be null");
string uniqueCode = Guid.NewGuid().ToString("N");
try
{
uniqueCode = await _generateUniqueCodeCommand.Process(context.CommerceContext);
}
catch(Exception ex)
{
context.CommerceContext.LogException($"{Name}-UniqueCodeException", ex);
}
order.OrderConfirmationId = uniqueCode;
return order;
}
}
}
ConfigureSitecore
The configure.sitecore
class is responsible to list, orchestrate, and register block definitions from all pipelines that a plugin defines. The pipeline configuration determines the sequence in which to run each pipeline blocks. When a pipeline starts up, it uses the information within the configure.sitecore
class to know which block to run. When you add a new custom block to an existing pipeline or when you create a new pipeline, you must insert your custom pipeline and blocks in the configure.sitecore
class so that it is processed in the required sequence.
The following is an example of the configure.sitecore
class that is provided with the sample Braintree payment provider plugin (included as part of the Commerce Engine SDK).
namespace Plugin.Sample.Payments.Braintree
{
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Sitecore.Commerce.Core;
using Sitecore.Commerce.Plugin.Orders;
using Sitecore.Commerce.Plugin.Payments;
using Sitecore.Framework.Configuration;
using Sitecore.Framework.Pipelines.Definitions.Extensions;
/// <summary>
/// The payments braintree configure sitecore class
/// </summary>
/// <seealso cref="Sitecore.Framework.Configuration.IConfigureSitecore" />
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(config => config
.ConfigurePipeline<IGetClientTokenPipeline>(d =>
{
d.Add<GetClientTokenBlock>().After<Sitecore.Commerce.Plugin.Payments.GetClientTokenBlock>();
})
.ConfigurePipeline<ICreateOrderPipeline>(d =>
{
d.Add<CreateFederatedPaymentBlock>().Before<CreateOrderBlock>();
})
.ConfigurePipeline<IReleaseOnHoldOrderPipeline>(d =>
{
d.Add<UpdateFederatedPaymentBlock>().After<ValidateOnHoldOrderBlock>();
})
.ConfigurePipeline<ISettleSalesActivityPipeline>(d =>
{
d.Add<SettleFederatedPaymentBlock>().After<ValidateSalesActivityBlock>()
.Add<UpdateOrderAfterFederatedPaymentSettlementBlock>().After<SettleFederatedPaymentBlock>();
})
.ConfigurePipeline<IRefundPaymentsPipeline>(d =>
{
d.Add<RefundFederatedPaymentBlock>().Before<PersistOrderBlock>();
})
.ConfigurePipeline<ICancelOrderPipeline>(d =>
{
d.Add<VoidCancelOrderFederatedPaymentBlock>().After<GetPendingOrderBlock>();
})
.ConfigurePipeline<IRunningPluginsPipeline>(c => { c.Add<RegisteredPluginBlock>().After<RunningPluginsBlock>(); }));
services.RegisterAllCommands(assembly);
}
}
}
Policies
A Commerce Engine policy is a group of settings that affects the behavior or functionality of a feature, or a Commerce micro-service, within the Commerce Engine. Commerce policies are typically driven by business needs and often affect storefront behaviors. Policies are heavily cached and rarely change their values outside of a deployment scenario. You configure policy settings using a .JSON
configuration file. A bootstrapping process initializes the configuration to a centralized policy store.
The following shows an example of a policy definition class (CartCouponsPolicy
):
using Sitecore.Commerce.Core;
namespace Sitecore.Commerce.Plugin.Coupons
{
/// <summary>
/// The CartCouponsPolicy.
/// </summary>
public class CartCouponsPolicy : QualifyPolicy
{
/// <summary>
/// Initializes a new instance of the <see cref="CartCouponsPolicy"/> class.
/// </summary>
public CartCouponsPolicy()
{ MaxCouponsInCart = 5;
}
/// <summary>
/// Gets or sets the maximum coupons in cart.
/// </summary>
/// <value>
/// The maximum coupons in cart.
/// </value>
public int MaxCouponsInCart { get; set; }
}
}
Minions
Commerce plugins can contribute minions. Commerce minions are worker processes, implemented as basic units of work to perform specific tasks in a process.