Hide menu Last updated: Oct 12 2015

With Episerver Commerce, you can create an order several ways through the order system API. This topic describes the main steps of the underlying mechanisms for order management.

Key classes

CartHelper

The CartHelper class acts as a common helper class for managing carts and orders. The CartHelper class is usually sufficient for many straightforward order placement scenarios. One advantage of the CartHelper class is that all required objects are automatically created in the background.

Example: adding an entry to a default cart via CartHelper

C#
Entry MyEntry = CatalogContext.Current.GetCatalogEntry(
entryCode,
new CatalogEntryResponseGroup(CatalogEntryResponseGroup.ResponseGroup.CatalogEntryFull)); CartHelper MyHelper = new CartHelper(Cart.DefaultName);MyHelper.AddEntry(MyEntry);

The only additional required step is the transformation of the cart to a PurchaseOrder.

Cart and OrderForm

Working with the Cart class and OrderForm class directly provides increased options and added flexibility, as compared with CartHelper classes. The following example uses the OrderForm, Cart, PurchaseOrder, LineItem and related classes.

Creating an order

The following example shows how to create an empty PurchaseOrder and store it in the database. The Cart class is used, and the SaveAsPurchaseOrder() method transforms the cart to a PurchaseOrder.

Example: creating an empty order

C#
Cart TheCart = OrderContext.Current.GetCart("MinimalOrder",CustomerContext.Current.CurrentContactId);
PurchaseOrder purchaseOrder = TheCart.SaveAsPurchaseOrder();
purchaseOrder.AcceptChanges();

Entities like OrderFormLineItem shipments and payments are still not in the order. The order is incomplete and cannot be properly loaded. While the CartHelper class takes care of this automatically, there are other ways of working with the order system.

Episerver Commerce can use several OrderForm instances in a single order. Most often, a single OrderForm is sufficient, but the platform supports a one-to-many relationship for most order system entities. The order API is therefore prepared for encountering several OrderForm instances in an order.

The code above creates a more or less empty OrderGroup database entry, with a name and a customer reference. The status is set to InProgress, which is correct. However, more steps must be taken for the order to be properly processed.

Adding OrderForm and shipment

The next example adds an OrderForm and the first Shipping so that you can add one or more LineItems.

Adding an order form

The following example opens up the order again and adds an OrderForm. The integer 114 is the OrderGroup primary key. An OrderGroup is like a bucket for a cart or an order.

Example: adding an order form

C#
PurchaseOrder purchaseOrder = OrderContext.Current.GetPurchaseOrderById(114);
OrderForm orderForm = new OrderForm();
purchaseOrder.OrderForms.Add(orderForm);
purchaseOrder.AcceptChanges();

As previously stated, there can be several OrderForms in an OrderGroup, and most often a single OrderForm is not sufficient. In this case, customization is required.

The following image shows that you can access an order by the UI after adding an OrderForm. Under the Details tab, there is no way of adding LineItems, since the order process is closely tied to shipments. However, from an API and database point of view, there are no restrictions of any kind.

Order Management Classes

Adding a shipment

Example: adding a shipment to the order

C#
Shipment TheShipment = new Shipment();
OrderForm orderForm = purchaseOrder.OrderForms[0];
ShippingMethodDto.ShippingMethodRow shippingMethodRow = null;
ShippingMethodDto allUsShipping = ShippingManager.GetShippingMethods("en-us");
foreach (ShippingMethodDto.ShippingMethodRow shipRow in allUsShipping.ShippingMethod)
{
  if (shipRow.DisplayName == "Ground Shipping")
  {
    shippingMethodRow = shipRow;
  }
}
TheShipment.ShippingMethodId = shippingMethodRow.ShippingMethodId;
TheShipment.ShippingMethodName = shippingMethodRow.DisplayName;
TheShipment.ShippingAddressId=
CustomerContext.Current.CurrentContact.PreferredShippingAddress.Name
TheShipment.ShipmentTotal = shippingMethodRow.BasePrice;
TheShipment.SetParent(orderForm);TheShipment.Status = OrderShipmentStatus.AwaitingInventory.ToString();

orderForm.Shipments.Add(TheShipment);
purchaseOrder.AcceptChanges();

You can add LineItems to the order from the user interface.

Order Management Classes

Under the Details tab, you can add LineItems to the order. However if the line is opened for editing, an exception such as this is thrown: Exception Details: System.NullReferenceException (there is nothing to edit). You can add LineItems via the UI and, when this is done, the line gets populated with values.

Note: Adding another shipment to a second OrderForm in the order does not show up, although it is added to the database and can be managed by the API. Also, the cost for additional shipping on additional OrderForms is not aggregated in the UI view by default.

Note: The Shipment Collection on the OrderForm class exposes methods like Add() and AddNew(), which are useful when adding shipments.

Adding line items to the order

You can add LineItems by the CartHelper (cart property) as shown above using the AddEntry(<Entry>) method. When you add the entry by CartHelper, everything else that is required is done in the background. But because you use a PurchaseOrder and not a Cart, this option is not available.

Note: The simplest way to add the entry is to use the Cart/CartHelper classes as far as possible. Then, at a certain point, convert the Cart to a PurchaseOrder for further coding.

Extending the order schema

To the LineItem class (LineItemEx) in MetaDataPlus, a custom field is added (LineItemExtraInfo) as a plain string field. This is done to differentiate properties between lines in an order, although it is the same SKU (not very commonly used). This option is not available if you use the CartHelper option.

Example: adding line items to an order

C#
// Load what is needed
PurchaseOrder purchaseOrder = OrderContext.Current.GetPurchaseOrderById(114);
OrderForm orderForm = purchaseOrder.OrderForms[0];
Shipment orderFormShipment = orderForm.Shipments[0];

// Get the Entry
Entry myEntry = CatalogContext.Current.GetCatalogEntry(
"049383208344",
new CatalogEntryResponseGroup(CatalogEntryResponseGroup.ResponseGroup.CatalogEntryFull)); Price price = StoreHelper.GetDiscountPrice(myEntry); // First LineItem LineItem MyLineItem = new LineItem(); MyLineItem.DisplayName = myEntry.Name; MyLineItem.CatalogEntryId = myEntry.ID; MyLineItem.Quantity = 1; MyLineItem.PlacedPrice = price.Amount; // Second LineItem LineItem MyOtherLineItem = new LineItem(); MyOtherLineItem.CatalogEntryId = myEntry.ID; MyOtherLineItem.DisplayName = myEntry.Name; MyOtherLineItem.Quantity = 1; MyOtherLineItem.PlacedPrice = price.Amount; orderForm.LineItems.Add(MyLineItem); // To have two lineItems for the same SKU, set the bool LineItemRollup (second arg.) to false orderForm.LineItems.Add(MyOtherLineItem, false); // Set it true and you will have the count of 2, for one single LineItem // The added custom MetaField (class LineItemEx) filled up orderForm.LineItems[0]["LineItemExtraInfo"] = "Item 1, nothing special"; orderForm.LineItems[1]["LineItemExtraInfo"] = "Item 2, very special"; // The following lines are needed to make the LineItems display // The shipping is closely tied to UI, but not related in such a way in the API PurchaseOrderManager.AddLineItemToShipment(
purchaseOrder,
orderForm.LineItems[0].LineItemId,
orderFormShipment,
1); PurchaseOrderManager.AddLineItemToShipment(
purchaseOrder,
orderForm.LineItems[1].LineItemId,
orderFormShipment,
1); purchaseOrder.OrderForms[0].Shipments.AcceptChanges(); orderForm.AcceptChanges();

You can add LineItems to an order without adding them to a shipment because orders are subject to change often and not immediately executed.

Adding payments

After you create a basic purchase order, add payment and shipment information. Exactly how this is done varies greatly depending on the site and integrations with other systems.

Payments

You can execute payment in many ways. The following example shows generic code used to associate a payment with the previously-created order.

Example: adding a payment

C#
PurchaseOrder purchaseOrder = OrderContext.Current.GetPurchaseOrderById(114);
OrderForm orderForm = purchaseOrder.OrderForms[0]; 

// using only one here
Payment ThePayment = null; // This is one is abstract, not an instantiable "PaymentMethod"
PaymentMethodDto paymentMethodDto = PaymentManager.GetPaymentMethodBySystemName
("Generic", "en-us");
Decimal amount = 0M;

foreach (LineItem l in orderForm.LineItems)
{
  amount += l.PlacedPrice;
}

OtherPayment otherPayment = new OtherPayment(); // the "real" payment-Type in MetaDataPlus
ThePayment = (Payment)otherPayment;
ThePayment.BillingAddressId = CustomerContext.Current.CurrentContact.PreferredBillingAddressId.ToString();
ThePayment.PaymentMethodName = paymentMethodDto.PaymentMethod[0].Name;
ThePayment.PaymentMethodId = paymentMethodDto.PaymentMethod[0].PaymentMethodId;
ThePayment.Amount = amount;
ThePayment.TransactionType = TransactionType.Sale.ToString();
ThePayment.Status = PaymentStatus.Pending.ToString();
ThePayment.SetParent(orderForm);
ThePayment.AcceptChanges();

orderForm.Payments.Add(ThePayment);
orderForm.AcceptChanges();

Split shipments

As Episerver Commerce has a one-to-many relation between most objects in the Order subsystem, LineItems of an order shipment can be split to a new shipment introduced in the order. This displays a message informing that overall totals do not match if a payment already has been created and managed in the UI.

If an additional shipment is added, an extra fee has to be paid. The order processing workflows detect that the payments do not match the total amount.

Example: splitting shipments

C#
Shipment existingShipment = purchaseOrder.OrderForms[0].Shipments[0];
//single OrderFormShipment newShipment = purchaseOrder.OrderForms[0].Shipments.AddNew();

PurchaseOrderManager.MoveLineItemToShipment(purchaseOrder,
  purchaseOrder.OrderForms[0].LineItems[1].LineItemId,
  existingShipment,
  newShipment,
  1);

existingShipment.AcceptChanges();
newShipment.AcceptChanges();

Split payments

Split payments are supported. Add the payments in the standard way and keep track of totals if payments are added by the API, as these properties are read.

Address information

The Order Management subsystem relies on MetaDataPlus as the metadata engine and for database storage. On the other hand, the Customer Management subsystem relies on Business Foundation (BF) for metadata, storage and definitions. This might lead to differences between the OrderAddress class in MetaDataPlus and the Address class in BF. The latter has a many-to-one relation in the CustomerContact class (a customer) but no direct relation or link to MetaDataPlus and OrderAddress. Depending on how the platform is used, order addresses can be useful.

ConvertToOrderAddress method exists at the StoreHelper class to help convert a customer address to an OrderAddress.

Key classes

Example: order addresses and display

C#
OrderAddress orderShipping = StoreHelper.ConvertToOrderAddress(
  CustomerContext.Current.CurrentContact.PreferredShippingAddress);
  purchaseOrder.OrderAddresses.Add(orderShipping);

OrderAddress orderBilling = StoreHelper.ConvertToOrderAddress(
  CustomerContext.Current.CurrentContact.PreferredBillingAddress);
   purchaseOrder.OrderAddresses.Add(orderBilling);

purchaseOrder.OrderAddresses.AcceptChanges();
 
// This is an "extra field" in the OrderGroup table (UI related) purchaseOrder.CustomerName = CustomerContext.Current.CurrentContactName; // Name of the orderform purchaseOrder.OrderForms[0].Name = "FirstOrderForm"; // Displaying the right billing address purchaseOrder.OrderForms[0].BillingAddressId = orderBilling.Name; purchaseOrder.OrderForms.AcceptChanges(); purchaseOrder.AcceptChanges();

Comments