Configure minion pipelines
You must add specific blocks to the index minion pipelines to ensure that the different indexing minions can handle each type of entity properly.
Full Index Minion and Incremental Index Minion pipelines
Insert a block into the IFullIndexMinionPipeline
and the IncrementalIndexMinionPipeline
respectively, to build document views for each entity type to be indexed.
You can use the InitializeOrdersIndexingViewBlock
(in the Orders plugin) or the InitializeCustomersIndexingViewBlock
(in the Customers plugin) as a reference.
public override Task<EntityView> Run(EntityView arg, CommercePipelineExecutionContext context)
{
Condition.Requires(arg).IsNotNull($"{this.Name}: argument cannot be null.");
var argument = context.CommerceContext.GetObjects<SearchIndexMinionArgument>().FirstOrDefault();
if (string.IsNullOrEmpty(argument?.Policy?.Name))
{
return Task.FromResult(arg);
}
var orders = argument.Entities?.OfType<Order>().ToList();
if (orders == null || !orders.Any())
{
return Task.FromResult(arg);
}
var searchViewNames = context.GetPolicy<KnownSearchViewsPolicy>();
orders.ForEach(
order =>
{
var documentView = arg.ChildViews.Cast<EntityView>()
.FirstOrDefault(v => v.EntityId.Equals(order.Id, StringComparison.OrdinalIgnoreCase) && v.Name.Equals(searchViewNames.Document, StringComparison.OrdinalIgnoreCase));
if (documentView == null)
{
documentView = new EntityView
{
Name = context.GetPolicy<KnownSearchViewsPolicy>().Document,
EntityId = order.Id
};
arg.ChildViews.Add(documentView);
}
var email = string.Empty;
var customerId = string.Empty;
if (order.HasComponent<ContactComponent>())
{
var contactComponent = order.GetComponent<ContactComponent>();
email = string.IsNullOrEmpty(contactComponent.Email) ? string.Empty : contactComponent.Email;
customerId = string.IsNullOrEmpty(contactComponent.CustomerId) ? string.Empty : contactComponent.CustomerId;
}
documentView.Properties.Add(new ViewProperty { Name = "EntityId", RawValue = Guid.Parse(order.Id).ToString("D") });
documentView.Properties.Add(new ViewProperty { Name = "Email", RawValue = email });
documentView.Properties.Add(new ViewProperty { Name = "CustomerId", RawValue = customerId });
documentView.Properties.Add(new ViewProperty { Name = "Status", RawValue = order.Status });
documentView.Properties.Add(new ViewProperty { Name = "OrderConfirmationId", RawValue = order.OrderConfirmationId });
documentView.Properties.Add(new ViewProperty { Name = "OrderPlacedDate", RawValue = order.OrderPlacedDate });
documentView.Properties.Add(new ViewProperty { Name = "DateCreated", RawValue = order.DateCreated });
documentView.Properties.Add(new ViewProperty { Name = "DateUpdated", RawValue = order.DateUpdated });
documentView.Properties.Add(new ViewProperty { Name = "ArtifactStoreId", RawValue = context.CommerceContext.Environment.ArtifactStoreId });
});
return Task.FromResult(arg);
}
Search View pipeline
If you want to modify the Search Results view, you can add a block to the SearchPipeline
(based on tags specified in the SearchView policy) to add more data to the search results.
You can use the ProcessDocumentSearchResultBlock
(in the Orders plugin) as a reference.
public override async Task<EntityView> Run(EntityView arg, CommercePipelineExecutionContext context)
{
Condition.Requires(arg).IsNotNull($"{this.Name}: argument can not be null.");
var documents = context.CommerceContext.GetObjects<List<Document>>().FirstOrDefault();
if (documents == null || !documents.Any())
{
return arg;
}
if (!arg.HasPolicy<SearchScopePolicy>())
{
return arg;
}
var scope = arg.GetPolicy<SearchScopePolicy>();
var hasTags = scope.ResultDetailsTags.Any(t => t.Name.Equals("OrdersList"));
if (!hasTags)
{
return arg;
}
foreach (var document in documents)
{
var docId = document["EntityId".ToLowerInvariant()].ToString();
var child = arg.ChildViews.OfType<EntityView>().FirstOrDefault(c => c.EntityId.Equals(docId, StringComparison.OrdinalIgnoreCase));
if (child == null)
{
continue;
}
Guid orderGuid;
if (!Guid.TryParse(docId, out orderGuid))
{
continue;
}
var orderId = orderGuid.ToString("B");
var order = await this._findPipeline.Run(new FindEntityArgument(typeof(CommerceEntity), orderId), context) as Order;
if (order == null)
{
continue;
}
var entityId = child.Properties.FirstOrDefault(p => p.Name.Equals("EntityId", StringComparison.OrdinalIgnoreCase));
if (entityId != null)
{
entityId.RawValue = orderId;
entityId.UiType = string.Empty;
entityId.IsHidden = true;
}
var confirmationId = child.Properties.FirstOrDefault(p => p.Name.Equals("OrderConfirmationId", StringComparison.OrdinalIgnoreCase));
if (confirmationId != null)
{
confirmationId.UiType = "EntityLink";
}
var customerId = child.Properties.FirstOrDefault(p => p.Name.Equals("CustomerId", StringComparison.OrdinalIgnoreCase));
if (customerId != null && order.HasComponent<ContactComponent>())
{
var contact = order.GetComponent<ContactComponent>();
if (contact.IsRegistered)
{
customerId.UiType = "Html";
var value = customerId.RawValue.ToString();
customerId.RawValue = $"<a href=\"/entityView/Master/{value}\">{contact.Email}</a>";
}
else
{
customerId.RawValue = contact.Email;
}
}
var status = child.Properties.FirstOrDefault(p => p.Name.Equals("Status", StringComparison.OrdinalIgnoreCase));
var total = new ViewProperty { Name = "total", RawValue = order.Totals.GrandTotal, IsReadOnly = true };
var placedDate = child.Properties.FirstOrDefault(p => p.Name.Equals("OrderPlacedDate", StringComparison.OrdinalIgnoreCase));
var updatedDate = child.Properties.FirstOrDefault(p => p.Name.Equals("DateUpdated", StringComparison.OrdinalIgnoreCase));
child.EntityId = orderId;
child.ItemId = orderId;
child.Properties.Clear();
child.Properties.Add(confirmationId);
child.Properties.Add(customerId);
child.Properties.Add(status);
child.Properties.Add(total);
child.Properties.Add(placedDate);
child.Properties.Add(updatedDate);
}
return arg;
}