Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
During checkout, Microsoft Workflow Foundation workflows are used to check remaining item stock quantity, and calculate the cart totals. EPiServer Commerce includes a checking inventory activity that is incorporated into the workflows. This will check the remaining warehouse inventory when adding or changing an item in a cart.
Classes referred to here are available in the following namespaces:
The CartPrepare workflow is run prior to rendering the page where the customer confirms the order.
This workflow performs the following tasks:
The determination of whether the items in the cart are still available, is done inside the CheckInventoryActivity activity.
Example: the CheckInventoryActivity activity
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Workflow.ComponentModel;
using Mediachase.Commerce.Orders;
namespace Mediachase.Commerce.Workflow.Activities
{
public partial class CheckInventoryActivity : OrderGroupActivityBase
{
/// <summary>
/// Initializes a new instance of the <see cref="CheckInventoryActivity"/> class.
/// </summary>
public CheckInventoryActivity()
{
InitializeComponent();
}
/// <summary>
/// Called by the workflow runtime to execute an activity.
/// </summary>
/// <param name="executionContext">The <see cref="T:System.Workflow.ComponentModel.ActivityExecutionContext"/> to associate with this <see cref="T:System.Workflow.ComponentModel.Activity"/> and execution.</param>
/// <returns>
/// The <see cref="T:System.Workflow.ComponentModel.ActivityExecutionStatus"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
/// </returns>
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
// Validate the properties at runtime
this.ValidateRuntime();
// Calculate order discounts
this.ValidateItems();
// Retun the closed status indicating that this activity is complete.
return ActivityExecutionStatus.Closed;
}
catch
{
// An unhandled exception occured. Throw it back to the WorkflowRuntime.
throw;
}
}
private void ValidateItems()
{
//We don't need to validate quantity in the wishlist
var orderForms = OrderGroup.OrderForms.ToArray();
var lineItems = orderForms.SelectMany(x => x.LineItems.ToArray());
var validLineItems = lineItems.Where(x => x.Code != "0" && !String.IsNullOrEmpty(x.Code) && !x.Code.StartsWith("@"));
foreach (LineItem lineItem in validLineItems)
{
List<string> changeQtyReason = new List<string>();
decimal newQty;
if (lineItem.IsInventoryAllocated)
{
newQty = lineItem.Quantity;
}
else
{
newQty = GetNewLineItemQty(lineItem, changeQtyReason, null);
}
var changeQtyReasonDisplay = String.Join(" and ", changeQtyReason.ToArray());
if (newQty == 0)
{
// Remove item if it reached this stage
Warnings.Add("LineItemRemoved-" + lineItem.LineItemId.ToString(), String.Format("Item \"{0}\" has been removed from the cart because it is no longer available or there is not enough available quantity.", lineItem.DisplayName));
DeleteLineItemFromShipments(lineItem);
// Delete item
lineItem.Delete();
}
else
{
var delta = lineItem.Quantity - newQty;
if (delta != 0)
{
lineItem.Quantity -= delta;
ChangeShipmentsLineItemQty(lineItem, delta);
Warnings.Add("LineItemQtyChanged-" + lineItem.LineItemId.ToString(),
String.Format("Item \"{0}\" quantity has been changed {1}", lineItem.DisplayName, changeQtyReasonDisplay));
}
}
}
//delete shipment if it has no item.
var shipments = orderForms.SelectMany(of => of.Shipments.ToArray());
foreach (Shipment shipment in shipments)
{
if (shipment.LineItemIndexes.Length == 0)
{
CancelOperationKeys(shipment);
shipment.Delete();
}
}
}
private void DeleteLineItemFromShipments(LineItem lineItem)
{
var orderForm = OrderGroup.OrderForms.ToArray().FirstOrDefault();
if (orderForm != null)
{
int lineItemIndex = orderForm.LineItems.IndexOf(lineItem);
var allShipmentContainsLineItem = orderForm.Shipments.ToArray().Where(x => Shipment.GetShipmentLineItems(x).Contains(lineItem));
foreach (var shipment in allShipmentContainsLineItem)
{
shipment.RemoveLineItemIndex(lineItemIndex);
}
ReorderIndexes(orderForm, lineItem);
}
}
private void ChangeShipmentsLineItemQty(LineItem lineItem, decimal delta)
{
var orderForm = OrderGroup.OrderForms.ToArray().FirstOrDefault();
if (orderForm != null)
{
var lineItemIndex = orderForm.LineItems.IndexOf(lineItem);
var allShipmentContainsLineItem = orderForm.Shipments.ToArray().Where(x => Shipment.GetShipmentLineItems(x).Contains(lineItem));
foreach (var shipment in allShipmentContainsLineItem)
{
//Decrease qty in all shipment contains line item
var shipmentQty = Shipment.GetLineItemQuantity(shipment, lineItem.LineItemId);
var newShipmentQty = shipmentQty - delta;
newShipmentQty = newShipmentQty > 0 ? newShipmentQty : 0;
//Set new line item qty in shipment
shipment.SetLineItemQuantity(lineItemIndex, newShipmentQty);
delta -= Math.Min(delta, shipmentQty);
if (delta == 0)
break;
}
}
}
}
}
If you wish to customize the checking inventory, you will need to create your own workflow which mirrors the CartPrepareWorkflow workflow, and substitutes the CheckInventoryActivity activity with your own implementation. Refer to Customizing order processing workflow for more information.
Last updated: Nov 12, 2014