Kentico CMS Quick Tip: Understanding E-Commerce XML Structures
Tags: kentico, cms, csharp, ecommerce
Published: 2019-11-18 14:40:07

---
title: Kentico CMS Quick Tip: Understanding E-Commerce XML Structures
published: true
description: Learn how Kentico stores E-Commerce data in XML in the database and which APIs developers can use to create this data.
tags: kentico, cms, csharp, ecommerce
series: Kentico Quick Tips
cover_image: https://thepracticaldev.s3.amazonaws.com/i/y6mb05yx1arbmpa8mhvj.jpg
---

<figcaption>Photo by <a href="https://unsplash.com/@thisisramiro">Ramiro Mendes</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

## E-Commerce Types and XML Data

Kentico's [documentation provides examples](https://docs.kentico.com/api12sp/e-commerce/orders) of ways that developers can interact with the `OrderInfo` and `OrderItemInfo` types 👍.

These are the primary objects developers retrieve order information from after a customer completes checkout with their shopping cart and an `OrderInfo` instance is created from the `ShoppingCartInfo` instance belonging to the customer.

However, it's not so clear from the documentation how all the fields in these objects get populated and what values we should expected to be stored in them 🤷🏽‍♀️.

This is especially true with the XML structures that Kentico uses for Summary and Custom Data fields, which we might find ourselves needing to parse for business logic customizations 🤨.

Below, we'll look at where these XML values come from and what schema we should expect them to use 🤓.

## OrderInfo fields

### OrderCustomData

**How do we populate it?**

This is one of a couple fields that is transparently copied from the `ShoppingCartInfo` to the `OrderInfo` when the order is created, so we can use either the `ShoppingCartInfo.ShoppingCartCustomData` or `OrderInfo.OrderCustomData`.

```csharp
// Via the ShoppingCartInfo
var shoppingService = Service.Resolve<IShoppingService>();

ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

cart.ShoppingCartCustomData.SetValue("CustomDataNumber", 42);
cart.ShoppingCartCustomData.SetValue("CustomDataString", "Hello");

cart.Update();
```

```csharp
// Via the OrderInfo
OrderInfo order = OrderInfoProvider.GetOrderInfo(23);

order.OrderCustomData.SetValue("CustomDataNubmer", 42);
order.OrderCustomData.SetValue("CustomDataString", "Hello");

order.Update();
```

**Where is it stored in the db?**

`COM_Order.OrderCustomData`

**What will it look like?**

```xml
<CustomData>
    <CustomDataNumber>42</CustomDataNumber>
    <CustomDataString>Hello</CustomDataString>
</CustomData>
```

---

### OrderPaymentResult

**How do we populate it?**

To set a payment result on an order we need to use the `OrderInfo.UpdateOrderStatus()` method, passing a valid `PaymentResultInfo`.

```csharp
var paymentResult = new PaymentResultInfo
{
    PaymentDate = DateTime.Now,
    PaymentDescription = "Test Payment completed",
    PaymentIsCompleted = true,
    PaymentIsAuthorized = true,
    PaymentTransactionID = Guid.NewGuid().ToString(),
    PaymentStatusValue = Guid.NewGuid().ToString(),
    PaymentMethodName = "TestPaymentName"
};

OrderInfo order = OrderInfoProvider.GetOrderInfo(23);

order.UpdateOrderStatus(paymentResult);

order.Update();
```

We can see below that each value populated in the `PaymentResultInfo` creates an element in the XML stored in the database.

The values like `{$PaymentGateway.Result.TransactionID$}` are unresolved [localization macros](https://docs.kentico.com/k12sp/macro-expressions/macro-syntax) that would be populated with translated values of the specific payment gateway / payment method being used for this order 🧐.

However, in my examples I have not populated those localization strings.

**Where is it stored in the db?**

`COM_Order.OrderPaymentResult`

**What will it look like?**

```xml
<result>
    <item name="date" 
        header="{$PaymentGateway.Result.Date$}" 
        value="11/17/2019 10:16:30 PM" />
    <item name="method" 
        header="{$PaymentGateway.Result.PaymentMethod$}" 
        text="TestPaymentName" />
    <item name="status" 
        header="{$PaymentGateway.Result.Status$}" 
        value="6a418f48-2aee-4bde-86ef-c6e3eef6667e" />
    <item name="transactionid" 
        header="{$PaymentGateway.Result.TransactionID$}" 
        value="237b5af1-bc28-4187-b9d4-0ecf1084b6ec" />
    <item name="description" 
        header="{$PaymentGateway.Result.Description$}" 
        value="Test Payment completed" />
    <item name="completed" 
        header="{$PaymentGateway.Result.IsCompleted$}" 
        value="1" text="{$PaymentGateway.Result.PaymentCompleted$}" />
    <item name="authorized" 
        header="{$PaymentGateway.Result.IsAuthorized$}" 
        value="1" text="{$paymentgateway.result.paymentauthorized$}" />
    <item name="failed" header="{$PaymentGateway.Result.IsFailed$}" />
</result>
```

---

### OrderDiscounts

**How do we populate it?**

Order discounts come from coupon codes defined in the CMS under the "Order Discounts" module.

In the example below I've created an Order Discount named `Test Discount 10%` that applies a 10% discount to the entire order.

Then I created a Coupon Code, `TEST_10_OFF`, for this discount.

```csharp
var shoppingService = Service.Resolve<IShoppingService>();

shoppingService.AddCouponCode("TEST_10_OFF");
```

**Where is it stored in the db?**

`COM_Order.OrderDiscounts`

**What will it look like?**

```xml
<Summary>
    <Item>
        <Name>Test Discount 10%</Name>
        <Value>0.30</Value>
    </Item>
</Summary>
```

---

### OrderOtherPayments

**How do we populate it?**

This field stores gift cards applied to the order, and in Kentico gift cards are basically coupons that reduce the final cost of the entire order and also the total balance of the gift card.

So, it shouldn't be much of a surprise that gift cards are added to an order the same way coupon codes are 😀.

For the example below, in the CMS "Gift Cards" module, I created a gift card named "Two Dollar Gift Card" with a coupon code `TWO_DOLLARS_PLEASE`.

```csharp
var shoppingService = Service.Resolve<IShoppingService>();

shoppingService.AddCouponCode("TWO_DOLLARS_PLEASE");
```

**Where is it stored in the db?**

`COM_Order.OrderOtherPayments`

**What will it look like?**

```xml
<Summary>
    <Item>
        <Name>Two Dollar Gift Card</Name>
        <Value>2.00</Value>
    </Item>
</Summary>
```

---

### OrderTaxSummary

**How do we populate it?**

Taxes for an order are calculated by an `ITaxCalculationService` which has a pretty simple signature, `TaxCalculationResult CalculateTaxes(TaxCalculationRequest taxRequest)`.

Kentico's documentation [has a good example](https://docs.kentico.com/k12sp/e-commerce-features/customizing-on-line-stores/customizing-tax-calculation) of how an implementation of this interface might look 💪🏿.

Here's a trivial example of an `ITaxCalculationService` that sets some values in the `TaxCalculationResult.Summary`.

```csharp
public class CustomTaxCalculationService : ITaxCalculationService
{
    public TaxCalculationResult CalculateTaxes(
        TaxCalculationRequest taxRequest)
    {
        var result = new TaxCalculationResult();

        decimal itemsTotal = ...

        result.ItemsTax = itemsTotal * .01m;

        result.Summary.Sum("Custom tax", itemsTotal * .027m);

        decimal shippingTaxRate = 0.15m;
        result.ShippingTax = taxRequest.ShippingPrice * shippingTaxRate;

        result.Summary.Sum("Custom shipping tax", result.ShippingTax);

        result.Summary.Sum("County Tax", itemsTotal * .06m);

        return result;
    }
}
```

We can see below how each of the `string` keys used in our call to `Summary.Sum()` (like `"County Tax"`) results in a element in the XML summary.

**Where is it stored in the db?**

`COM_Order.OrderTaxSummary`

**What will it look like?**

```xml
<Summary>
    <Item>
        <Name>Custom tax</Name>
        <Value>0.270</Value>
    </Item>
    <Item>
        <Name>Custom shipping tax</Name>
        <Value>0.000</Value>
    </Item>
    <Item>
        <Name>County Tax</Name>
        <Value>0.1620</Value>
    </Item>
</Summary>
```

---

### OrderCouponCodes

**How do we populate it?**

By applying any coupons to an order we can populate the `OrderCouponCodes` field - this include both order discount coupons and gift card coupons.

> These are the coupons that result in the `OrderOtherPayments` and `OrderDiscounts` fields being populated 🧐.

This field will also contain any "Product Coupons" (see `OrderItemDiscountSummary` below) applied to the order, even though these are order item specific.

```csharp
var shoppingService = Service.Resolve<IShoppingService>();

// Apply an order discount
shoppingService.AddCouponCode("TEST_10_OFF");

// Apply a gift card
shoppingService.AddCouponCode("TWO_DOLLARS_PLEASE");
```

**Where is it stored in the db?**

`COM_Order.OrderCouponCodes`

**What will it look like?**

```xml
<CouponCodes>
    <CouponCode>
        <Code>TEST_10_OFF</Code>
    </CouponCode>
    <CouponCode>
        <Code>TWO_DOLLARS_PLEASE</Code>
        <ValueInMainCurrency>2.00</ValueInMainCurrency>
    </CouponCode>
</CouponCodes>
```

---

## OrderItem fields

### OrderItemCustomData

**How do we populate it?**

This field works just like `OrderInfo.OrderCustomData`, except it allows us to store custom data per line-item in the order. This means we can use either `ShoppingCartItemInfo.CartItemCustomData` or `OrderItemInfo.OrderItemCustomData`.

```csharp
// Via the ShoppingCartItemInfo
var shoppingService = Service.Resolve<IShoppingService>();

ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

ShoppingCartItemInfo cartItem = cart.CartItems.First();

cartItem.CartItemCustomData.SetValue("CustomDataNumber", 10);
cartItem.CartItemCustomData.SetValue("CustomDataString", "Hello");

cartItem.Update();
```

```csharp
// Via the OrderItemInfo
ICollection<OrderItemInfo> orderItems = OrderItemInfoProvider
    .GetOrderItems(orderId);

OrderItemInfo orderItem = orderItems.First();

orderItem.OrderItemCustomData.SetValue("CustomDataNumber", 10);
orderItem.OrderItemCustomData.SetValue("CustomDataString", "Hello");

orderItem.Update();
```

**Where is it stored in the db?**

`COM_OrderItem.OrderItemCustomData`

**What will it look like?**

```xml
<CustomData>
    <CustomDataNumber>10</CustomDataNumber>
    <CustomDataString>Hello</CustomDataString>
</CustomData>
```

---

### OrderItemProductDiscounts

**How do we populate it?**

This field is populated by any catalog discounts we have defined for our store in the CMS. These can be managed in the "Catalog Discounts" module.

For the example below, I've created a catalog discount named "Test Product 5% off" which applies a percentage discount of 5% to a single product named "Test Product".

This means the "Test Product" needs to be in my order for this discount to be applied and the field to be populated ✔.

```csharp
SKUInfo sku = SKUInfoProvider
    .GetSKUs()
    .WhereEquals(nameof(SKUInfo.SKUName), "TestProduct")
    .TopN(1)
    .FirstOrDefault();

var shoppingService = Service.Resolve<IShoppingService>();

ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

shoppingService.AddItemToCart(sku.SKUID, 1);
```

> Note that this is the one discount/coupon related field where the discount value and not the discounted amount is stored.

> So, for example, a `Value` of "0.05" for a catalog discount of 5% would be stored and not "1.00" for a 10% discount on a $10.00 product.

> All other discount/coupon fields store the amount to be subtracted from the order or item price.

**Where is it stored in the db?**

`COM_OrderItem.OrderItemProductDiscounts`

**What will it look like?**

```xml
<Summary>
    <Item>
        <Name>Test Product 5% off</Name>
        <Value>0.05</Value>
    </Item>
</Summary>
```

---

### OrderItemDiscountSummary

**How do we populate it?**

This field is populated when the order has items that are part of a Buy->Get type discount, which are defined in the CMS "Buy X Get Y" module.

These kinds of discounts state that if a customer purchases some set of products they will get a discount of some amount either on specific items (in order to encourage buying products together) or on the cheapest items in the cart (as a promotion) 🤔.

In the example below I have a discount defined that applies a 20% discount named "Test Buy X Get Y" on the product named "Test Accessory" if the order also has a product named "Test Product".

```csharp
SKUInfo skuProduct = SKUInfoProvider
    .GetSKUs()
    .WhereEquals(nameof(SKUInfo.SKUName), "TestProduct")
    .TopN(1)
    .FirstOrDefault();

SKUInfo skuAccessory = SKUInfoProvider
    .GetSKUs()
    .WhereEquals(nameof(SKUInfo.SKUName), "TestAccessory")
    .TopN(1)
    .FirstOrDefault();

var shoppingService = Service.Resolve<IShoppingService>();

ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

shoppingService.AddItemToCart(skuProduct.SKUID, 1);
shoppingService.AddItemToCart(skuAccessory.SKUID, 1);
```

We can also populate this field with coupons created in the "Product Coupons" CMS module.

If we add a coupon to the shopping cart that applies to a product in the cart, the Product Coupon display name and the discount amount will be stored in the XML.

**Where is it stored in the db?**

`COM_OrderItem.OrderItemDiscountSummary`

**What will it look like?**

```xml
<Summary>
    <Item>
        <Name>Test Buy X Get Y</Name>
        <Value>0.20</Value>
    </Item>
</Summary>
```

---

## Summary

Kentico has all sorts of nooks and crannies, hiding implementation details. Some times the defaults fulfill the needs of our business logic, but other times we need to explore these thins to understand how we can best apply customizations 🤓.

We've looked at how the XML fields of `ShoppingCartInfo`, `ShoppingCartItemInfo`, `OrderInfo`, and `OrderItemInfo` are populated, used, and stored in the database.

These fields can usually be ignored until we explicitly need them, and in those cases it's nice to have some concrete examples, like the ones above, to ensure the results we are seeing in our applications are the correct ones.

Hopefully this blog post can be a little cheat-sheet for you (and me! 😎) when working with Kentico's E-Commerce functionality.

Thanks for reading 🙏!

---

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

Or my Kentico blog series:

- [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%3A%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)