Lab 08b – Checkout: Creating and Viewing Orders
Contents
TOC \o “1-3” \h \z \u HYPERLINK \l “_Toc536538667” Lab 08b – Checkout: Creating and Viewing Orders PAGEREF _Toc536538667 \h 1
HYPERLINK \l “_Toc536538668” 1. Working with orders, PAGEREF _Toc536538668 \h 1
HYPERLINK \l “_Toc536538669” 2. Displaying Order Data- PAGEREF _Toc536538669 \h 3
HYPERLINK \l “_Toc536538670” 3. Displaying order details PAGEREF _Toc536538670 \h 5
HYPERLINK \l “_Toc536538671” 3. Place the Order PAGEREF _Toc536538671 \h 7
HYPERLINK \l “_Toc536538672” 4. Save the Order in the Database PAGEREF _Toc536538672 \h 10
HYPERLINK \l “_Toc536538673” 5. Update Product deletion to avoid foreign key conflicts. PAGEREF _Toc536538673 \h 11
HYPERLINK \l “_Toc536538674” 6. Searching and Sorting Orders PAGEREF _Toc536538674 \h 12
These instructions cover,
working with orders,
creating them via a checkout process,
viewing the details of orders as either an administrator or a user and
searching or sorting them.
We don’t cover any payment provider integration.
We are going to add a one-to-many relationship between users and orders, where a user can have many orders but an order is placed only by a single user.
Working with orders,
Add two new classes to the Models folder, and name them: Order.cs and OrderLine.cs
public class Order
{
[Display(Name = “Order ID”)]
public int OrderID { get; set; }
[Display(Name = “User ID”)]
public string UserID { get; set; }
[Display(Name = “Delivery Name”)]
public string DeliveryName { get; set; }
[Display(Name = “Delivery Address”)]
public Address DeliveryAddress { get; set; }
[Display(Name = “Total Price”)]
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = “{0:c}”)]
public decimal TotalPrice { get; set; }
public DateTime DateCreated { get; set; }
public List
}
public class OrderLine
{
public int ID { get; set; }
public int OrderID { get; set; }
public int? ProductID { get; set; }
public int Quantity { get; set; }
public string ProductName { get; set; }
[Display(Name = “Unit Price”)]
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = “{0:c}”)]
public decimal UnitPrice { get; set; }
public virtual Product Product { get; set; }
public virtual Order Order { get; set; }
}
Update StoreContext.cs file as follows:
public class StoreContext:DbContext
{
public DbSet
public DbSet
public DbSet
public DbSet
public DbSet
public DbSet
public DbSet
Create sample order data and update the database; in Migrations\StoreConfig.cs, add the following code (based on your own data); Ensure that using System is at the top of the file. Also make sure, the categories and product exist in your inventory before you are creating an order for it.
var orders = new List
{
new Order { DeliveryAddress = new Address { AddressLine1=”1 Some Street”, Town=”Town1″,
Country=”Country”, PostCode=”PostCode” }, TotalPrice=631,
UserID=”admin@example.com”, DateCreated=new DateTime(2014, 1, 1) ,
DeliveryName=”Admin” },
new Order { DeliveryAddress = new Address { AddressLine1=”1 Some Street”, Town=”Town1″,
Country=”Country”, PostCode=”PostCode” }, TotalPrice=239,
UserID=”admin@example.com”, DateCreated=new DateTime(2014, 1, 2) ,
DeliveryName=”Admin” },
new Order { DeliveryAddress = new Address { AddressLine1=”1 Some Street”, Town=”Town1″,
Country=”Country”, PostCode=”PostCode” }, TotalPrice=239,
UserID=”admin@example.com”, DateCreated=new DateTime(2014, 1, 3) ,
DeliveryName=”Admin” },
new Order { DeliveryAddress = new Address { AddressLine1=”1 Some Street”, Town=”Town1″,
Country=”County”, PostCode=”PostCode” }, TotalPrice=631,
UserID=”admin@example.com”, DateCreated=new DateTime(2014, 1, 4) ,
DeliveryName=”Admin” },
new Order { DeliveryAddress = new Address { AddressLine1=”1 Some Street”, Town=”Town1″,
Country=”Country”, PostCode=”PostCode” }, TotalPrice=19.49M,
UserID=”admin@example.com”, DateCreated=new DateTime(2014, 1, 5) ,
DeliveryName=”Admin” }
};
orders.ForEach(c => context.Orders.AddOrUpdate(o => o.DateCreated, c));
context.SaveChanges();
var orderLines = new List
{
new OrderLine { OrderID = 1, ProductID = products.Single( c=> c.Name == “Lenovo 510″).ID,
ProductName =”Lenovo 510”, Quantity =1, UnitPrice=products.Single( c=> c.Name == “Lenovo 510”).Price },
new OrderLine { OrderID = 2, ProductID = products.Single( c=> c.Name == “ASUS VE248″).ID,
ProductName=”ASUS VE248″, Quantity=1, UnitPrice=products.Single( c=> c.Name ==”ASUS VE248”).Price },
new OrderLine { OrderID = 3, ProductID = products.Single( c=> c.Name == “ASUS VE248″).ID,
ProductName =”ASUS VE248”, Quantity=1, UnitPrice=products.Single( c=> c.Name == “ASUS VE248”).Price },
new OrderLine { OrderID = 4, ProductID = products.Single( c=> c.Name == “Lenovo 510″).ID,
ProductName =”Lenovo 510”, Quantity=1, UnitPrice=products.Single( c=> c.Name == “Lenovo 510”).Price },
new OrderLine { OrderID = 5, ProductID = products.Single( c=> c.Name == “8Ware USB Blutooth”).ID,
ProductName =”8Ware USB Blutooth”, Quantity=1, UnitPrice=products.Single( c=> c.Name == “8Ware USB Blutooth”).Price }
};
orderLines.ForEach(c => context.OrderLines.AddOrUpdate(ol => ol.OrderID, c));
context.SaveChanges();
The above code specifies that Admin user has some orders placed.
Next open the package manager console and add the following commands one by one.
PM> add-migration addorders -Configuration StoreConfiguration
PM> update-database -Configuration StoreConfiguration
If you now open your database, you should be able to see your new tables, Orders and OrderLines.
Displaying Order Data-
Add an OrdersController class as depicted below, Using MVC5 Controller with Views using Entity Framework:
Displaying a List of Orders; first to make an order or view orders, make sure that the person is logged in. To do that, first annotate the OrdersController class with [Authorize] as shown below:
[Authorize]
public class OrdersController : Controller
{
Next update the OrdersController.cs Index() method as below:
// GET: Orders
public ActionResult Index()
{
if (User.IsInRole(“Admin”))
{
return View(db.Orders.ToList());
}
else
{
return View(db.Orders.Where(o => o.UserID == User.Identity.Name));
}
}
Next modify the auto-generated Views\Orders\Index.cshtml file.
@model IEnumerable
@{
ViewBag.Title = “Orders”;
}
@ViewBag.Title
@Html.DisplayNameFor(model => model.OrderID) | @Html.DisplayNameFor(model => model.UserID) | @Html.DisplayNameFor(model => model.DeliveryName) | @Html.DisplayNameFor(model => model.DeliveryAddress) | @Html.DisplayNameFor(model => model.TotalPrice) | @Html.DisplayNameFor(model => model.DateCreated) | |
---|---|---|---|---|---|---|
@Html.DisplayFor(modelItem => item.OrderID) | @Html.DisplayFor(modelItem => item.UserID) | @Html.DisplayFor(modelItem => item.DeliveryName) | @Html.DisplayFor(modelItem => item.DeliveryAddress) | @Html.DisplayFor(modelItem => item.TotalPrice) | @Html.DisplayFor(modelItem => item.DateCreated) |
@*@Html.ActionLink(“Edit”, “Edit”, new { id=item.OrderID }) |*@ @Html.ActionLink(“Details”, “Details”, new { id=item.OrderID }) | @*@Html.ActionLink(“Delete”, “Delete”, new { id=item.OrderID })*@ |
Now run the program to see the new index method displaying the list if the user is Admin.
Displaying order details
First update the Details method of the OrdersController class as follows:
// GET: Orders/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//Order order = db.Orders.Find(id);
Order order = db.Orders.Include(o => o.OrderLines).Where(o => o.OrderID == id).SingleOrDefault();
if (order == null)
{
return HttpNotFound();
}
if (order.UserID == User.Identity.Name || User.IsInRole(“Admin”))
{
return View(order);
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
}
Update the Views\Orders\Details.cshtml as follows:
@model OnlineStore.Models.Order
@{
ViewBag.Title = “Order Details”;
}
@ViewBag.Title
Item(s)
Quantity
Unit Price
@foreach(var item in Model.OrderLines)
{
}
- @Html.DisplayNameFor(model => model.TotalPrice)
- @Html.DisplayFor(model => model.TotalPrice)
- @Html.DisplayNameFor(model => model.OrderID)
- @Html.DisplayFor(model => model.OrderID)
- @Html.DisplayFor(model => model.UserID)
- @Html.DisplayNameFor(model => model.DeliveryName)
- @Html.DisplayFor(model => model.DeliveryName)
- @Html.DisplayNameFor(model => model.DeliveryAddress)
- @Html.DisplayFor(model => model.DeliveryAddress)
- @Html.DisplayNameFor(model => model.TotalPrice)
- @Html.DisplayFor(model => model.TotalPrice)
- @Html.DisplayNameFor(model => model.DateCreated)
- @Html.DisplayFor(model => model.DateCreated)
@*@Html.ActionLink(“Edit”, “Edit”, new { id = Model.OrderID }) |*@
@Html.ActionLink(“Back to List”, “Index”)
Now if you log in, you will be able to see the details page, after clicking the details on orders\index page if you are an Admin.
Place the Order
Update the OrdersController class as follows- it takes the code from UsersAdminController.cs –
update the directives – using Microsoft.AspNet.Identity.Owin;
[Authorize]
public class OrdersController : Controller
{
private StoreContext db = new StoreContext();
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager
}
private set
{
_userManager = value;
}
}
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get
}
private set
{
_roleManager = value;
}
}
// GET: Orders
public ActionResult Index()
{
if (User.IsInRole(“Admin”))
….Rest of the code is same
Next change the name of the OrdersController.cs Create() method to Review() and update the code as follows: – Always right-click and rename so that the dependencies are changed too as depicted:
Don’t Include strings or comments
Also, Update the directives and add – using System.Threading.Tasks;
// GET: Orders/Create
public async Task
{
Basket basket = Basket.GetBasket();
Order order = new Models.Order();
order.UserID = User.Identity.Name;
ApplicationUser user = await UserManager.FindByNameAsync(order.UserID);
order.DeliveryName = user.FirstName + ” ” + user.LastName;
order.DeliveryAddress = user.Address;
order.OrderLines = new List
foreach (var basketLine in basket.GetBasketLines())
{
OrderLine line = new OrderLine
{
Product = basketLine.Product,
ProductID = basketLine.ProductID,
ProductName = basketLine.Product.Name,
Quantity = basketLine.Quantity,
UnitPrice = basketLine.Product.Price
};
order.OrderLines.Add(line);
}
order.TotalPrice = basket.GetTotalCost();
return View(order);
}
Now rename the Views\Orders\Create.cshtml to Views\Orders\Review.chtml and update the code as follows:
@model OnlineStore.Models.Order
@{
ViewBag.Title = “Review your Order”;
}
@ViewBag.Title
@using (Html.BeginForm(“Create”, “Orders”))
{
@Html.AntiForgeryToken()
Order
@Html.ValidationSummary(true, “”, new { @class = “text-danger” })
@foreach (var item in Model.OrderLines)
{
}
@Html.HiddenFor(model => Model.TotalPrice)
@Html.HiddenFor(model => Model.UserID)
@Html.ValidationMessageFor(model => model.DeliveryName, “”, new { @class = “text-danger” })
@Html.EditorFor(model => model.DeliveryAddress)
}
@section Scripts {
@Scripts.Render(“~/bundles/jqueryval”)
}
Update the Views\Basket\Index.cshtml file to make the users review their orders:
…………………Code omitted here to save space, you don’t cut it from the code.
—-