---
title: Building the order review step
related:
  - https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process.md
  - https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process/gathering-customer-details-during-checkout.md
  - https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders.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).

> **Info:** This page is part three of the [Implementing a checkout process](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process.md) series.

In this part of the series, we look at the final step in a conventional checkout process – order review. An order review step usually details selected products and entered address, payment, and shipping details to the [customer](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/customers.md). After a customer reviews these details and finalizes the order, the page often redirects them to a summary, displaying the order ID and a thank you message. If the customer selected a suitable [payment method](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-payment-methods.md), this might be preempted by a [redirection to a payment gateway](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process/building-the-order-review-step/connecting-to-payment-gateways.md).

On this page, we will implement the part of the checkout process that:

- Displays customer information collected in the [previous step](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process/gathering-customer-details-during-checkout.md) alongside the contents of the customer's shopping cart.
- Allows customers to select a payment method and complete their order.
- Displays a thank you page summarizing the order.

> **Tip:** **Tip**: View the full code of a functional example in the [LearningKit project](https://github.com/Kentico/LearningKit-Mvc) on GitHub. You can also run the LearningKit website by connecting the project to a Xperience database. Follow the instructions in the repository's README file.

Open your live site project in Visual Studio and:

1. Create a view model for payment methods. The model stores select properties of the _PaymentOptionInf&#x6F;_&#x6F;bject type from the _CMS.Ecommerce_ namespace.

   ```csharp

       public class PaymentMethodViewModel
       {
           [DisplayName("Payment method")]
           public int PaymentMethodID { get; set; }

           public SelectList PaymentMethods { get; set; }

           /// <summary>
           /// Creates a payment method model.
           /// </summary>
           /// <param name="paymentMethod">Selected payment method.</param>
           /// <param name="paymentMethods">List of all available payment methods.</param>
           public PaymentMethodViewModel(PaymentOptionInfo paymentMethod, SelectList paymentMethods)
           {
               PaymentMethods = paymentMethods;

               if (paymentMethod != null)
               {
                   PaymentMethodID = paymentMethod.PaymentOptionID;
               }
           }

           /// <summary>
           /// Creates an empty payment method model.
           /// Required by the MVC framework for model binding during form submission.
           /// </summary>
           public PaymentMethodViewModel()
           {
           }
       }


   ```
2. Create a view model used to aggregate data collected in the previous steps. This model aggregates the _DeliveryDetailsViewModel_ and _ShoppingCartViewModel_ models created in the previous parts of this series. It also holds the _PaymentMethodViewModel_ created in the previous step.

   ```csharp

       public class PreviewAndPayViewModel
       {
           public DeliveryDetailsViewModel DeliveryDetails { get; set; }

           public ShoppingCartViewModel Cart { get; set; }

           public PaymentMethodViewModel PaymentMethod { get; set; }

       }


   ```
3. Add new actions to the **CheckoutController**class that:

   - Retrieve valid [payment methods](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-payment-methods.md).

     ```csharp

             /// <summary>
             /// Gets all applicable payment methods assigned to the current site.
             /// </summary>
             /// <param name="cart">Shopping cart of the site</param>
             /// <returns>Collection of applicable payment methods</returns>
             private IEnumerable<PaymentOptionInfo> GetApplicablePaymentMethods(ShoppingCartInfo cart)
             {
                 // Gets all enabled payment methods from Xperience
                 IEnumerable<PaymentOptionInfo> enabledPaymentMethods = paymentOption.GetBySite(SiteContext.CurrentSiteID, true).ToList();

                 // Returns all applicable payment methods
                 return enabledPaymentMethods.Where(paymentMethod => PaymentOptionInfoProvider.IsPaymentOptionApplicable(cart, paymentMethod));
             }


     ```

     > **Tip:** To limit available payment methods based on the selected shipping option, see [Making payment methods dependent on shipping options](https://docs.kentico.com/13/e-commerce-features/customizing-on-line-stores/payment-related-customizing/making-payment-methods-dependent-on-shipping-options.md).
   - Fill the _PreviewAndPayViewModel_ and send it to the related view template.

     ```csharp

             /// <summary>
             /// Display the preview checkout process step.
             /// </summary>
             public ActionResult PreviewAndPay()
             {
                 // If the current shopping cart is empty, returns to the shopping cart action
                 if (shoppingService.GetCurrentShoppingCart().IsEmpty)
                 {
                     return RedirectToAction("ShoppingCart");
                 }

                 // Prepares a model from the preview step
                 PreviewAndPayViewModel model = PreparePreviewViewModel();

                 // Displays the preview step
                 return View(model);
             }

             /// <summary>
             /// Prepares a view model of the preview checkout process step including the shopping cart,
             /// the customer details, and the payment method.
             /// </summary>
             /// <returns>View model with information about the future order.</returns>
             private PreviewAndPayViewModel PreparePreviewViewModel()
             {
                 // Gets the current user's shopping cart
                 ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

                 // Prepares the customer details
                 DeliveryDetailsViewModel deliveryDetailsModel = new DeliveryDetailsViewModel
                 {
                     Customer = new CustomerViewModel(shoppingService.GetCurrentCustomer()),
                     BillingAddress = new BillingAddressViewModel(shoppingService.GetBillingAddress(), null, null),
                     ShippingOption = new ShippingOptionViewModel()
                     {
                         ShippingOptionID = cart.ShippingOption.ShippingOptionID,
                         ShippingOptionDisplayName = shippingOption.Get(cart.ShippingOption.ShippingOptionID).ShippingOptionDisplayName
                     }
                 };

                 // Prepares the payment method
                 PaymentMethodViewModel paymentViewModel = new PaymentMethodViewModel
                 {
                     PaymentMethods = new SelectList(GetApplicablePaymentMethods(cart), "PaymentOptionID", "PaymentOptionDisplayName")
                 };

                 // Gets the selected payment method
                 PaymentOptionInfo paymentMethod = cart.PaymentOption;
                 if (paymentMethod != null)
                 {
                     paymentViewModel.PaymentMethodID = paymentMethod.PaymentOptionID;
                 }

                 // Prepares a model from the preview step
                 PreviewAndPayViewModel model = new PreviewAndPayViewModel
                 {
                     DeliveryDetails = deliveryDetailsModel,
                     Cart = new ShoppingCartViewModel(cart),
                     PaymentMethod = paymentViewModel
                 };

                 return model;
             }

             /// <summary>
             /// Decides whether the specified payment method is valid on the current site.
             /// </summary>
             /// <param name="paymentMethodID">ID of the applied payment method.</param>
             /// <returns>True if the payment method is valid.</returns>
             private bool IsPaymentMethodValid(int paymentMethodID)
             {
                 // Gets the current shopping cart
                 ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

                 // Gets a list of all applicable payment methods to the current user's shopping cart
                 List<PaymentOptionInfo> paymentMethods = GetApplicablePaymentMethods(cart).ToList();

                 // Returns whether an applicable payment method exists with the entered payment method's ID
                 return paymentMethods.Exists(p => p.PaymentOptionID == paymentMethodID);
             }


     ```
4. Add an action to the controller that processes the order. If the processing is successful, the action displays a [payment page](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process/building-the-order-review-step/connecting-to-payment-gateways.md).

   ```csharp

           /// <summary>
           /// Validates all collected information, creates an order,
           /// and redirects the customer to payment.
           /// </summary>
           /// <param name="model">View model with information about the future order.</param>
           [HttpPost]
           public ActionResult PreviewAndPay(PreviewAndPayViewModel model)
           {
               // Gets the current shopping cart
               ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

               // Validates the shopping cart
               var validationErrors = ShoppingCartInfoProvider.ValidateShoppingCart(cart);

               // Gets the selected payment method, assigns it to the shopping cart, and evaluates the cart
               shoppingService.SetPaymentOption(model.PaymentMethod.PaymentMethodID);

               // If the validation was not successful, displays the preview step again
               if (validationErrors.Any() || !IsPaymentMethodValid(model.PaymentMethod.PaymentMethodID))
               {
                   // Prepares a view model from the order review step
                   PreviewAndPayViewModel viewModel = PreparePreviewViewModel();

                   // Displays the order review step again
                   return View("PreviewAndPay", viewModel);
               }

               // Creates an order from the current shopping cart
               // If the order was created successfully, empties the cart
               OrderInfo order = shoppingService.CreateOrder();

               // Redirects to the payment gateway
               return RedirectToAction("Index", "Payment", new { orderID = order.OrderID });
           }


   ```

   > **Tip:** If you provide only [manual payment methods](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-payment-methods.md) (and therefore do not require connections to any [payment gateways](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process/building-the-order-review-step/connecting-to-payment-gateways.md)), you can redirect your customers directly to a thank-you page. For example:
   >
   > ```csharp
   >
   >         /// <summary>
   >         /// Displays a thank-you page where user is redirected after creating an order.
   >         /// </summary>
   >         /// <param name="orderID">ID of the created order.</param>
   >         public ActionResult ThankYou(int orderID = 0)
   >         {
   >             ViewBag.OrderID = orderID;
   >
   >             return View();
   >         }
   >
   >
   > ```
   >
   > The related view template may, for example, display a short 'thank you' message and an order summary:
   >
   > ```csharp
   >
   > @{
   >     Layout = "~/Views/Shared/_Layout.cshtml";
   >     ViewBag.Title = "Thank-you page";
   > }
   >
   > <h2>Thank-you page</h2>
   >
   > <p>Order number: @ViewBag.OrderID</p>
   > <p>Your order was succesfully created. Thank you for your patronage!</p>
   >
   >
   > ```
5. Create a view for the order review step. For example:

   ```csharp

   @* Displays the customer details. *@
   <div id="customerDetails">
       <h2>Customer Details</h2>
       <div>
           @Html.LabelFor(m => m.DeliveryDetails.Customer.FirstName):
           @Html.DisplayFor(m => m.DeliveryDetails.Customer.FirstName)
       </div>
       <div>
           @Html.LabelFor(m => m.DeliveryDetails.Customer.LastName):
           @Html.DisplayFor(m => m.DeliveryDetails.Customer.LastName)
       </div>
       <div>
           @Html.LabelFor(m => m.DeliveryDetails.Customer.Company):
           @if (!(String.IsNullOrEmpty((string)Model.DeliveryDetails.Customer.Company))) {
               Html.DisplayFor(m => m.DeliveryDetails.Customer.Company);
           } else { Html.Raw("none"); }
       </div>
   </div>

   @* Lists all products from the shopping cart. *@
   <div id="cartContent">
       <h3>Ordered products</h3>
       <ul>
           @* Loops through all shopping cart items. *@
           @foreach (ShoppingCartItemViewModel cartItem in Model.Cart.CartItems)
           {
               @* Displays the shopping cart item's properties. *@
               <li>
                   @cartItem.CartItemUnits&times; @cartItem.SKUName ... @String.Format(Model.Cart.CurrencyFormatString, cartItem.TotalPrice)
               </li>
               }
       </ul>
   </div>

   @* Displays additional order details. *@
   <div id="shoppingCartTotals">
       <p>Selected shipping method: @Model.DeliveryDetails.ShippingOption.ShippingOptionDisplayName</p>
       <p>Total tax: @String.Format(Model.Cart.CurrencyFormatString, Model.Cart.TotalTax)</p>
       <p>Total shipping: @String.Format(Model.Cart.CurrencyFormatString, Model.Cart.TotalShipping)</p>
       <p>Total (incl. tax): @String.Format(Model.Cart.CurrencyFormatString, Model.Cart.GrandTotal)</p>
   </div>

   @* Invokes a POST action finalizing order creation. *@
   @using (Html.BeginForm("PreviewAndPay", "Checkout", FormMethod.Post))
   {
       <div id="paymentMethod">
           @Html.LabelFor(m => m.PaymentMethod.PaymentMethodID):
           @Html.DropDownListFor(m => m.PaymentMethod.PaymentMethodID, Model.PaymentMethod.PaymentMethods)
       </div>

       <input type="submit" value="Create an order" />
   }


   ```

Customers are now able to select their preferred payment method, and review and confirm their order. When a customer creates an order, Xperience sends a notification email to the email address specified in the [Send order notification setting](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-e-commerce-email-notifications.md).
