Add Button to Check Out the Shopping Cart Contents Task The first web layer task is to add a button to the DisplayShoppingCart.aspx so that users can start the process of placing their o
Trang 1OdbcCommand dataCommand = new OdbcCommand();
dataCommand.Connection = dataConnection;
// Build command stringStringBuilder commandText =new StringBuilder("DELETE FROM [Orders Details] WHERE OrdersID = ");
commandText.Append(orderID);
commandText.Append(" and ProductID = ");
commandText.Append(productID);
dataCommand.CommandText = commandText.ToString();
int rows = dataCommand.ExecuteNonQuery();
// Make sure that the DELETE workedAssert.AreEqual(1, rows, "Unexpected Orders Details row count, gasp!");
dataConnection.Close();
lineItem = null;
}catch(Exception e){
Assert.Fail("Orders Details database error: " + e.Message);
}}}}
Listing 15-10.OrderDetailData.cs File
#region Using derectives
}
Trang 2public static int InsertLineItem(int orderID, LineItem lineItem){
int rows = -1;
try{Product product = lineItem.Item;
OdbcConnection dataConnection = new OdbcConnection();
dataConnection.ConnectionString = DataUtilities.ConnectionString;dataConnection.Open();
OdbcCommand dataCommand = new OdbcCommand();
dataCommand.Connection = dataConnection;
// Build command stringStringBuilder commandText =new StringBuilder("INSERT INTO [Orders Details] (");
Console.WriteLine(e.Message);
}
Trang 3return rows}
}}
Listing 15-11.OrderDetail.cs File
#region Using directives
private int orderID;
private int productID;
private decimal unitPrice;
private int quantityOrdered;
private float discount;
public OrderDetail(){
}public OrderDetail(int orderID,int productID,
decimal unitPrice,int quantityOrdered,float discount){
Trang 4public int OrderID{
get{return this.orderID;
}set{this.orderID = value;
}}public int ProductID{
get{return this.productID;}
set{this.productID = value;}
}public decimal UnitPrice{
get{return this.unitPrice;}
set{this.unitPrice = value;}
}public int QuantityOrdered{
get{return this.quantityOrdered;}
set{this.quantityOrdered = value;}
}
Trang 5public float Discount{
get{return this.discount;
}set{this.discount = value;
}}}}
This concludes the test, data, and business classes You should be able to successfullybuild and test the entire solution Once you have resolved any build or test issues, you are
ready to move on to the web layer
Add Button to Check Out the Shopping Cart Contents Task
The first web layer task is to add a button to the DisplayShoppingCart.aspx so that users
can start the process of placing their order Listing 15-12 shows the updated
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
<%@ Page language="c#" CodeFile="DisplayShoppingCart.aspx.cs"
Trang 6<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
Trang 7This will take the user to the CheckOutConfirmation.aspx page.
Create Checkout Confirmation Page Task
Now that the DisplayShoppingCart.aspx page allows the user to check out, you need to build
the confirmation page called CheckoutConfirmation.aspx, as shown in Listing 15-13
Listing 15-13.CheckoutConfirmation.aspx File
<%@ Import Namespace="BusinessLayer" %>
<%@ Import Namespace="DataLayer" %>
<%@ Import Namespace="System.Collections" %>
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
Trang 8<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
Display Shopping Cart Contents in Checkout Confirmation Page Task
You will need to retrieve the shopping cart that you have been building and display its tents To do that, enhance CheckoutConfirmation.aspx as shown in Listing 15-14
con-Listing 15-14.Modified CheckoutConfirmation.aspx to Show Shopping Cart Contents
<%@ Import Namespace="BusinessLayer" %>
<%@ Import Namespace="DataLayer" %>
<%@ Import Namespace="System.Collections" %>
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
Trang 9<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
LineItem lineItem = (LineItem)cartEnumerator.Value;
Product product = lineItem.Item;
Trang 10shop-Listing 15-15.Modified CheckoutConfirmation.aspx.cs to Get the Shopping Cart
protected ShoppingCart cart = null;
protected IDictionaryEnumerator cartEnumerator = null;
protected void Page_Load(object sender, System.EventArgs e){
if ( Session["cart"] != null ){
cart = (ShoppingCart)Session["cart"];
}else{cart = new ShoppingCart();
cart.Quantity = 0;
Session["cart"] = cart;
}cartEnumerator = cart.GetCartContents();
}}
Now when the users go to this page, if they have any items in their shopping cart, thoseitems will be displayed But this isn’t much different from the DisplayShoppingCart.aspx page
So, next you will subtotal the dollar amounts of all the items displayed
Subtotal Shopping Cart Line Items and Display Results Task
To get the subtotal, you need to first enhance CheckoutConfirmation.aspx to display the tal, as shown in Listing 15-16
Trang 11subto-Listing 15-16.Modified CheckoutConfirmation.aspx to Show the Subtotal
<%@ Import Namespace="BusinessLayer" %>
<%@ Import Namespace="DataLayer" %>
<%@ Import Namespace="System.Collections" %>
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
LineItem lineItem = (LineItem)cartEnumerator.Value;
Product product = lineItem.Item;
Response.Write("<tr><td>" + product.ProductName + "</td><td>"
Trang 12+ product.Price.ToString("C") + "</td><td align=\"center\">"+ lineItem.Quantity.ToString() + "</td></tr>");
total += product.Price * lineItem.Quantity;
protected ShoppingCart cart = null;
protected IDictionaryEnumerator cartEnumerator = null;
protected decimal total = 0;
Trang 13protected void Page_Load(object sender, System.EventArgs e){
if ( Session["cart"] != null ){
cart = (ShoppingCart)Session["cart"];
}else{cart = new ShoppingCart();
cart.Quantity = 0;
Session["cart"] = cart;
}cartEnumerator = cart.GetCartContents();
}}}
Now you can display the subtotal Next, you need to add a button to cancel checking out
in case users change their mind
Add Button to Cancel the Checkout Task
For the next task, you will add a button to CheckoutConfirmation.aspx that will allow users to
exit the checkout process and return to their shopping experience Listing 15-18 shows the
enhanced CheckoutConfirmation.aspx page
Listing 15-18.CheckoutConfirmation.aspx with a Cancel Button
<%@ Import Namespace="BusinessLayer" %>
<%@ Import Namespace="DataLayer" %>
<%@ Import Namespace="System.Collections" %>
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
Trang 14<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
LineItem lineItem = (LineItem)cartEnumerator.Value;
Product product = lineItem.Item;
Response.Write("<tr><td>" + product.ProductName + "</td><td>"+ product.Price.ToString("C") + "</td><td align=\"center\">"+ lineItem.Quantity.ToString() + "</td></tr>");
total += product.Price * lineItem.Quantity;
Trang 15<td colspan="2" align="right">
<form id="login" method="post" runat="server">
<asp:Button ID="CancelButton" runat="server" Text="Cancel"></asp:Button>
protected ShoppingCart cart = null;
protected IDictionaryEnumerator cartEnumerator = null;
protected decimal total = 0;
protected void Page_Load(object sender, System.EventArgs e){
if ( Session["cart"] != null ){
cart = (ShoppingCart)Session["cart"];
}else{cart = new ShoppingCart();
cart.Quantity = 0;
Trang 16Session["cart"] = cart;
}cartEnumerator = cart.GetCartContents();
}protected void CancelButton_Click(Object sender, System.EventArgs e){
Response.Redirect("DisplayShoppingCart.aspx", true);
}}}
Add Button to Process Order Request Task
The last task is to add a button to CheckoutConfirmation.aspx that will act as acceptance of theuser’s intention to check out and process the order First, you will add the button to the page,
<%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %>
<%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %>
<td width="20%" valign="top" align="left">
<Categories:LeftNav id="leftnav" runat="server" />
</td>
Trang 17LineItem lineItem = (LineItem)cartEnumerator.Value;
Product product = lineItem.Item;
<form id="login" method="post" runat="server">
<asp:Button id="CompleteOrderButton" runat="server"
Trang 18Then you will enhance the CheckoutConfirmation.aspx.cs class with a method to handlethe Complete Order button click, as shown in Listing 15-21.
Listing 15-21.CheckoutConfirmation.aspx.cs with an Order Completion Method
protected ShoppingCart cart = null;
protected IDictionaryEnumerator cartEnumerator = null;
protected decimal total = 0;
private void Page_Load(object sender, System.EventArgs e){
if ( Session["cart"] != null ){
cart = (ShoppingCart)Session["cart"];
}else{cart = new ShoppingCart();
cart.Quantity = 0;
Session["cart"] = cart;
}cartEnumerator = cart.GetCartContents();
}protected void CompleteOrderButton_Click(Object sender, System.EventArgs e){
// Get the current customerUser user = (User)Session["User"];
Customer customer = CustomerData.FindCustomerByUserName(user.UserName);
Trang 19// Create the new Orderint orderID = OrderData.InsertOrder(customer);
// Do order completion stuff and redirect to OrderConfirmation pagecart = (ShoppingCart)Session["cart"];
cartEnumerator = cart.GetCartContents();
while (cartEnumerator.MoveNext()){
LineItem lineItem = (LineItem)cartEnumerator.Value;
OrderDetailData.InsertLineItem(orderID, lineItem);
lineItem.Item.Quantity -= lineItem.Quantity;
ProductData.UpdateQuantity(lineItem.Item);
}// Empty the cartSession["cart"] = null;
Response.Redirect("OrderConfirmation.aspx?orderID=" + orderID, true);
}protected void CancelButton_Click(object sender, System.EventArgs e){
Response.Redirect("DisplayShoppingCart.aspx", true);
}}}
The User class in the BusinessLayer will need to be updated This class should look likeListing 15-22
Listing 15-22.Updated User.cs File
#region Using directives
private string userName;
private string password;
Trang 20public User(){
}public User(string userName, string password){
this.userName = userName;
this.password = password;
}public string UserName{
get{return this.userName;
}set{this.userName = value;
}}public string Password{
get{return this.password;
}set{this.password = value;
}}}}
In addition, the ProductData class in the DataLayer will need to updated, as shown in Listing 15-23
Listing 15-23.Updated ProductData.cs File
#region Using directives
Trang 21}public static ArrayList GetProductsByCategory(int categoryID){
ArrayList products = new ArrayList();
try{OdbcConnection dataConnection = new OdbcConnection();
Product product = new Product();
Trang 22}catch(Exception e){
Console.WriteLine("Error: " + e.Message);
}return products;
}public static Product GetProduct(int ProductID){
Product product = null;
try{OdbcConnection dataConnection = new OdbcConnection();
dataConnection.ConnectionString = DataUtilities.ConnectionString;dataConnection.Open();
OdbcCommand dataCommand = new OdbcCommand();
dataCommand.Connection = dataConnection;
// Build command stringStringBuilder commandText =new StringBuilder("SELECT * FROM Products WHERE ProductID = ");commandText.Append(productID);
dataCommand.CommandText = commandText.ToString();
OdbcDataReader dataReader = dataCommand.ExecuteReader();
if (dataReader.Read()){
product = new Product();
}catch (Exception e){
Console.WriteLine("Error: " + e.Message);
}
Trang 23return product;
}public static ArrayList SearchForProducts(string searchString){
ArrayList products = new ArrayList();
try{OdbcConnection dataConnection = new OdbcConnection();
product = new Product();
}catch (Exception e){
Console.WriteLine("Error: " + e.Message);
}return products;
}
Trang 24public static void UpdateQuantity(Product product){
try{OdbcConnection dataConnection = new OdbcConnection();
Console.WriteLine(e.Message);
}}}}
This should complete all the tasks for the Display Checkout Confirmation user story Butremember that a story is not complete until the customer says so That is where the accept-ance test for this user story comes into play
Acceptance Testing
The acceptance test for a story is defined by the customer and automated (if possible) by theacceptance tester Our customer defined the acceptance test for the Display Checkout Confir-mation user story as follows:
• Click a Checkout button on the Display Shopping Cart page to check out
• Display a Checkout Confirmation page that lists all the items currently in the shoppingcart
• See a subtotal dollar amount of the order
Trang 25• When a Continue button is clicked on the Checkout Confirmation page, the ordershould be built and handed off for processing.
• A Cancel button should also be displayed on the Checkout Confirmation page Whenclicked, that button should take the user back to the Display Shopping Cart page
Developing the Remaining User Stories
This iteration has four other user stories As in the first iteration, they are being developed in
parallel with the Display Checkout Confirmation user story, which we focused on here Each
user story has its own acceptance tests written by the customer and automated by the
accept-ance testers, where possible
The developers switch pairs at least once a day They take a test-driven approach with theremaining user stories, just as with the user story described in this chapter
All the developers keep track of the time they spend on the tasks that they picked for thisiteration When the tracker comes around (at least twice a week), the developers report the
actual time they have spent on their tasks
You can download the source code for this iteration from the Source Code area of theApress website (www.apress.com)
Coach’s Journal
During this iteration, I noticed that the team is getting better at pairing The pairs were better
at switching who was on the keyboard and who was not I also saw that the team members are
getting more acclimated to their environment, and that overall communication is starting to
occur more frequently and openly
Also, the acceptance testers are getting more comfortable with testing early rather thanlater The acceptance testers were extremely helpful in working with the customer to define
the acceptance tests and determining what could be automated
As in the last iteration, I spoke with our customer frequently to make sure that he wascomfortable with what was going on during the iteration When our customer had concerns or
questions, I addressed them immediately This iteration, our customer became keenly aware
of a need for securing the website during the ordering process I sat down with him, and we
discussed several options that he had in this area I can see that he is already thinking about
security stories for the next release
Summary
By now, you should be getting a feel for the XP process You have seen how to take a
test-driven development approach to coding You have witnessed how an iterative approach can
provide a lot of feedback in the form of unit and acceptance tests Daily stand-ups and the
graphs and charts generated by the tracker create a better environment for communication
All of this communication allows the team members to better gauge where they are at meeting
their targets
You are well on your way down the XP path