---
title: Displaying and updating orders
related:
  - https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders.md
  - https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders/order-statuses.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

A common aspect of many on-line stores is a section where customers can review their past orders and inspect each one in detail.

Usually, such sections allow users to:

- Display information about an order's current processing status to a customer
- Provide a summary of the order's contents and related information, such as its [status](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders/order-statuses.md) or payment results
- Display a list of all orders a customer has made

## Preparing the controller class

Initialize an instance of the _IShoppingService_, _ICurrencyInfoProvider_ and _IOrderInfoProvider_ interfaces in the controller you use to handle order-related functionality. _ShoppingService,_ the default implementation of the _IShoppingService_ interface, facilitates various E-commerce scenarios.

The _ICurrencyInfoProvider_ instance is later used in the order view model to get the order's currency and formatting information. _IOrderInfoProvider_ is used for basic getting and setting (saving) of order objects.

```csharp

        /// <summary>
        /// Initializes instances of service used to facilitate shopping cart, currency and order interactions.
        /// </summary>
        public OrderController(IShoppingService shoppingService,
                               ICurrencyInfoProvider currencyInfoProvider,
                               IOrderInfoProvider orderInfoProvider,
                               ISiteService siteService)
        {
            this.shoppingService = shoppingService;
            this.currencyInfoProvider = currencyInfoProvider;
            this.orderInfoProvider = orderInfoProvider;
            this.siteService = siteService;
        }


```

See our [API reference](https://devnet.kentico.com/documentation) for a complete list of API exposed by the _IShoppingService_ interface.

> **Tip:** We recommend using a [dependency injection container](https://docs.kentico.com/13/developing-websites/initializing-xperience-services-with-dependency-injection.md) to initialize instances of used API services (e.g. _IShoppingService_).

After you have prepared your controller class, you can implement new actions that:

- [Display an order and allow updates of its status](#displaying-and-updating-a-specific-order)
- [Display a list of orders](#displaying-a-list-of-orders)
- [Provide the ability to reorder (add products from a past order to the shopping cart) ](#reordering-existing-orders)

## Displaying and updating a specific order

To display and update a specific order:

1. Implement new action methods that retrieve an order based on a specified ID.

   ```csharp title="Getting an order"

           /// <summary>
           /// Displays a page where order details can be listed.
           /// </summary>
           public ActionResult OrderDetail()
           {
               OrderViewModel order = null;

               return View(order);
           }

           /// <summary>
           /// Displays details about an order specified with its ID.
           /// </summary>
           /// <param name="textBoxValue">Order ID as a string</param>
           [HttpPost]
           public ActionResult OrderDetail(string textBoxValue)
           {
               // Gets the order based on the entered order ID
               OrderViewModel order = GetOrderViewModel(textBoxValue);

               return View(order);
           }

           /// <summary>
           /// Returns the order view model wrapper based on the entered ID.
           /// </summary>
           /// <param name="textBoxValue">String containing the user-entered order ID</param>
           /// <returns>View model object of the order</returns>
           private OrderViewModel GetOrderViewModel(string textBoxValue)
           {
               OrderInfo info = GetOrder(textBoxValue);

               OrderViewModel order = (info == null) ? null : new OrderViewModel(info, currencyInfoProvider);

               return order;
           }

           /// <summary>
           /// Returns the order based on the entered order ID.
           /// </summary>
           /// <param name="textOrderID">String containing the user-entered order ID</param>
           /// <returns>Order object of the order</returns>
           private OrderInfo GetOrder(string textOrderID)
           {
               Int32.TryParse(textOrderID, out int orderID);

               // If the text value is not a number, returns null
               if (orderID <= 0)
               {
                   return null;
               }

               // Gets the order based on the order ID
               OrderInfo order = orderInfoProvider.Get(orderID);

               // Gets the current customer
               CustomerInfo customer = shoppingService.GetCurrentCustomer();

               var currentSiteID = siteService.CurrentSite.SiteID;
               // Validates that the order was created on the current site and that it belongs to the current customer
               if ((order?.OrderSiteID != currentSiteID) || (order?.OrderCustomerID != customer?.CustomerID))
               {
                   order = null;
               }

               return order;
           }


   ```

   > **Note:** _IOrderInfoProvider.Get(int)_ returns any order with the given ID, provided it exists. Any necessary validation, for instance if the order belongs to the correct customer, or was made on the current site, is the responsibility of the developer. See [Ensuring validation](#ensuring-validation) for more information.
   >
   > The example above validates whether the specified order was created on the current site, and whether it belongs to the current customer. Should any of these conditions be violated, it returns a _null_ value.
2. Prepare a view model to store select properties of the _OrderInfo_ object for display in the related view.

   ```csharp

       public class OrderViewModel
       {
           public int OrderID { get; set; }

           public int OrderStatusID { get; set; }

           public string CurrencyFormatString { get; set; }

           public DateTime OrderDate { get; set; }

           public decimal OrderTotalPrice { get; set; }

           public bool OrderIsPaid { get; set; }

           public OrderPaymentResultViewModel OrderPaymentResult { get; set; }

           public string OrderStatusDisplayName { get; set; }

           public OrderViewModel(OrderInfo order, ICurrencyInfoProvider currencyInfoProvider)
           {
               OrderID = order.OrderID;
               OrderStatusID = order.OrderStatusID;
               CurrencyFormatString = currencyInfoProvider.Get(order.OrderCurrencyID).CurrencyFormatString;
               OrderDate = order.OrderDate;
               OrderTotalPrice = order.OrderTotalPrice;
               OrderIsPaid = order.OrderIsPaid;
               OrderStatusDisplayName = OrderStatusInfo.Provider.Get(order.OrderStatusID)?.StatusDisplayName;
               if (order.OrderPaymentResult != null)
               {
                   OrderPaymentResult = new OrderPaymentResultViewModel()
                   {
                       PaymentMethodName = order.OrderPaymentResult.PaymentMethodName,
                       PaymentIsCompleted = order.OrderPaymentResult.PaymentIsCompleted
                   };
               }
           }
       }


   ```
3. Implement a new action method that updates the specified order as required. For example, you can allow store managers to set orders as paid for:

   ```csharp title="Setting an order as paid"

           /// <summary>
           /// Marks an order specified by an order ID as paid.
           /// </summary>
           /// <param name="textBoxValue">Order ID as a string</param>
           [HttpPost]
           public ActionResult MarkOrderAsPaid(string textBoxValue)
           {            
               // Gets the order based on the entered order ID
               OrderInfo order = GetOrder(textBoxValue);

               // Sets the order as paid
               order.OrderIsPaid = true;
               orderInfoProvider.Set(order);

               return RedirectToAction("OrderDetail");
           }


   ```
4. Prepare a view with the content required for your order detail page. For example:

   ```xml

   @* Renders a form field for entering order IDs. *@
   @using (Html.BeginForm("OrderDetail", "Order"))
   {    
       <input type="text" name="TextBoxValue" />
       <input type="submit" name="DisplayOrder" value="Display order" />
   }

   @if (Model != null)
   {
       <h2>Order details</h2>
       @* Displays order details. *@
       <ul>
           <li>Order number: @Model.OrderID</li>
           <li>Status ID: @Model.OrderStatusID</li>
           <li>Is paid: @Model.OrderIsPaid</li>
           @if (Model.OrderPaymentResult != null)
           {
               <li>Payment method name: @Model.OrderPaymentResult.PaymentMethodName</li>
               <li>Was payment successful: @Model.OrderPaymentResult.PaymentIsCompleted</li>
           }
           <li>Total price: @String.Format(Model.CurrencyFormatString, Model.OrderTotalPrice)</li>
       </ul>
       @* If the order is not paid for, renders a button invoking the 'MarkOrderAsPaid' action that marks the order as paid. *@
       if (!Model.OrderIsPaid)
       {
           using (Html.BeginForm("MarkOrderAsPaid", "Order"))
           {
               <input type="text" hidden="hidden" name="TextBoxValue" value="@Model.OrderID" />
               <input type="submit" name="MarkOrderAsPaid" value="Mark order as paid" />
           }
       }
   }


   ```

Users are now able to display details of a specific order by entering its ID. If the order is not paid for, they are also able to set its status as paid.

## Displaying a list of orders

Displaying a list of orders is suitable especially for "My orders" sections in customers' accounts.

1. Add an action to the controller that manges the retrieval of current customer's orders, creates a collection, and displays it in a related view. The examples uses _OrderViewModel_ from the [Displaying and updating a specific order](#displaying-and-updating-a-specific-order) section to store select _OrderInfo_ object properties.

   ```csharp

           /// <summary>
           /// Displays a listing of the current user's orders.
           /// </summary>
           public ActionResult MyOrders()
           {            
               // Gets the current customer
               CustomerInfo currentCustomer = shoppingService.GetCurrentCustomer();

               // If the customer does not exist, returns error 404
               if (currentCustomer == null)
               {
                   return HttpNotFound();
               }

               // Retrieves from the database a collection of all orders made by the current customer 
               var orders = orderInfoProvider.GetBySite(siteService.CurrentSite.SiteID)
                                                              .WhereEquals("OrderCustomerID", currentCustomer.CustomerID)
                                                              .OrderByDescending(orderInfo => orderInfo.OrderDate);

               // Creates a list of view models representing the collection of a customer's orders
               IList<OrderViewModel> model = orders
                           .Select(order => new OrderViewModel(order, currencyInfoProvider))
                           .ToList();

               return View(model);
           }


   ```

   > **Note:** The _IOrderInfoProvider.GetBySite call_ retrieves all orders created by a customer with the provided ID. Any validation, is the responsibility of the developer. See [Ensuring validation](#ensuring-validation) for more information.
2. Prepare a view with the content required for your order detail page. For example:

   ```xml

   @model IEnumerable<OrderViewModel>

   @if (Model.Any())
   {
       <h3>Your orders:</h3>
       @* Ensures basic formatting of the displayed information. *@
       <table>
           <thead>
               <tr>
                   <th>Id</th>
                   <th>Date</th>
                   <th>Status</th>
                   <th>Total</th>
                   <th></th>
               </tr>
           </thead>
           @* Iterates over all orders in the collection and displays their properties. *@
           @foreach (var order in Model)
           {
               <tr>
                   <td>
                       @order.OrderID
                   </td>
                   <td>
                       @order.OrderDate
                   </td>
                   <td>
                       @(order.OrderStatusDisplayName)
                   </td>
                   <td>
                       @String.Format(order.CurrencyFormatString, order.OrderTotalPrice)
                   </td>
                   <td>
                       @using (Html.BeginForm("Reorder", "Order", FormMethod.Post))
                       {
                           @Html.Hidden("OrderId", order.OrderID)
                           <input type="submit" value="Reorder" />
                       }
                   </td>
               </tr>
           }
       </table>
   }


   ```

Your live site application is now able to list all orders a customer has created.

## Reordering existing orders

To add the contents of an existing order directly into the customer's shopping cart, call _ShoppingCartInfoProvider.UpdateShoppingCartFromOrder._ The method iterates over all products in the specified order and adds them to the shopping cart accounting for any [Buy X, get Y](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-buy-x-get-y-discounts.md) discounts, [product bundles](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/products/managing-product-representations/managing-bundles.md), sales, and other promotions the store might be running at the time.

The following example demonstrates the usage of this method in a controller action:

```csharp

        /// <summary>
        /// Recreates shopping cart content based on a specified order.
        /// </summary>
        /// <param name="orderId">ID of an order to repurchase</param>
        [HttpPost]
        public ActionResult Reorder(int orderId)
        {           
            // Gets the current shopping cart
            ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

            // Adds products from the specified order to the current shopping cart
            // If the operation was successful, redirects to the shopping cart
            if (ShoppingCartInfoProvider.UpdateShoppingCartFromOrder(cart, orderId))
            {
                // Displays the shopping cart
                return RedirectToAction(nameof(CheckoutController.ShoppingCart), "Checkout");
            }

            // If the reorder was unsuccessful, returns back to the list of customer's orders
            return RedirectToAction(nameof(MyOrders));
        }


```

## Ensuring validation

The Xperience _InfoProvider_ and _ObjectQuery_ API works with data retrieved directly from the database. Ensuring that data retrieved this way satisfies required constraints and other input criteria is the responsibility of the MVC site's developer.

Common validation checks that we recommend you employ are:

- Null checks – these validate the existence of objects retrieved via API.
- Checks for matching _SiteContext.CurrentSiteID_ and _OrderInfo.OrderSiteID_ properties – in enviroments where there are multiple e-commerce sites running on the same instance, the same customer could have created orders on more than one site. These checks validate that the retrieved orders were created on the current site.
- Checks for matching _CustomerInfo.CustomerID_ and _OrderInfo.OrderCustomerID_ properties – these validate whether the order belongs to the customer with the given ID.
