Shopping Cart with Arrays & Structures/E-Commerce - Part 3
Shopping Cart/E-Commerce Tutorial
Using Arrays & Structures
-Part 3 of 3-
By Michael Bamberger

Tutorial Index
#Section Title
1. Database Layout
2. Member Sign Up
3. *Main Shopping Cart Page
4. *Product Display - "Add to Cart"
5. Checkout - Order Processing
6. Supplemental Coding - Navigation Include

This part of the tutorial deals with having the customer check out and process their order. Additionally, it contains special code snippets that you will find helpful and will want to revert back to as you build your shopping cart.

Section 5 - Checkout - Order Processing
Now our customers have products in their cart and they're ready to submit their order. So, there are a number of things we have to do. Firstly, we have to check to see if our customer is logged in. If they're not, we have to give them the option to log in. If they don't have an account, we give them the option to sign up. Here is our checkout.cfm page:

checkout.cfm - The inital checkout page.
<cfif session.allowin NEQ "True">

<table cellpadding="3" cellspacing="0" border="0" align="center" width="100%">
<tr>
<td valign="top">
<div>Customer Sign In</div>
<form name="CustSignIn" action="checkout_signin.cfm" method="post">
<table width="350" border="0" align="center" cellspacing="0" cellpadding="5" style="font-weight:bold;border:2px solid #DDDDDD;">
<tr>
<td><b>E-mail Address:</b></td>
<td><input type="text" name="username" value="" size="25"></td>
</tr>
<tr>
<td><b>Password:</b></td>
<td><input type="password" name="password" value="" size="25"></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Sign In"></td>
</tr>
</table>
</form>
</td>
<td>
<div>New Customer Sign Up</div>
*****SAME FORM AS ABOVE SIGN UP PAGE*****
</td>
</tr>
</table>

<cfelse>

<script>
self.location="confirmorder.cfm";
</script>
</cfif>


So what we do in this file is first check to see if the user is logged in (session.allowin). If they are not, we show them our page. Our page gives them the option to log in or sign up a new account. Notice how it is not inconvenient to sign up a new account. The user can simply sign up just as if it were a normal checkout (without membership). The only difference is they have to choose a password.
At the bottom of the page, we see the <cfelse> tag that is finishing off the initial cfif tag checking if our customer is logged in. If they ARE logged in, we forward them to our next page, confirmorder.cfm.

confirmorder.cfm - The order checking page.
<cfif session.allowin NEQ "True">
You must sign in before your order can be confirmed.
<cfelse>
<cfquery name="logMem" datasource="test">
SELECT *
FROM LCustomers
WHERE username = '#session.username#'
</cfquery>
<cfif logMem.cc_type EQ "">
You do not have a credit card on file.
<cfelseif logMem.cc_num EQ "">
You do not have a credit card number on file.
<cfelseif logMem.cc_expir_m EQ "">
You do not have sufficient credit card information on file.
<cfelseif logMem.cc_expir_y EQ "">
You do not have sufficient credit card information on file.
<cfelse>


<cfquery name="logMem" datasource="test">
SELECT *
FROM LCustomers
WHERE username = '#session.username#'
</cfquery>

<cfinclude template="ordertotals.cfm">

<div>Order Confirmation</div>
<div style="font-size:8pt;">
Your order information is outlined below. To process this order, please click the button below. The expenses will be charged to the credit card listed on file.<br>
<form name="ConfirmOrder" action="processorder.cfm" method="post">
<input type="submit" value="Click Here to Process This Order">
</form>
</div>
<cfoutput>
<table width="320" border="0" cellpadding="3" cellspacing="0" style="border:2px solid ##DDDDDD;font-size:8pt;">
<tr>
<td colspan="2" style="font-size:11pt;font-weight:bold;background-color:##DDDDDD;">Customer Information</td>
</tr>
<tr style="background-color:##FFFFFF;">
<td valign="top"><b>Customer Name</b>:</td><td>#logMem.c_fname# #logMem.c_lname#</td>
</tr>
<tr style="background-color:##FFFFFF;">
<td valign="top"><b>Address</b>:</td><td>#logMem.c_street#<br>#logMem.c_city#, #logMem.c_state# #logMem.c_zip#</td>
</tr>
<tr style="background-color:##FFFFFF;">
<td valign="top"><b>Credit Card:</b></td><td>#logMem.cc_type#<br>xxxx-xxxx-xxxx-#Right(logMem.cc_num,4)#</td>
</tr>
</table>
</cfoutput><br>

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0" style="border:2px solid #DDDDDD;">
<tr>
<td colspan="6" style="font-size:11pt;font-weight:bold;background-color:#DDDDDD;">Order Breakdown</td>
</tr>
<tr>
<td><b>#</b></td><td><b>Product</b></td><td><b>Size</b></td><td><b>Unit Price</b></td><td><b>Quantity</b></td><td><b>Total</b></td>
</tr>
<cfoutput>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
<tr style="background-color:##<cfif i MOD 2>EFEFEF<cfelse>FFFFFF</cfif>;">
<td>#i#</td>
<td>#session.shoppingcart[i].name#</td>
<td>#session.shoppingcart[i].size#</td>
<td>#DollarFormat(session.shoppingcart[i].price)#</td>
<td>#session.shoppingcart[i].quantity#</td>
<td>#DollarFormat(total[i])#</td>
</tr>
</cfloop>
</cfoutput>

<tr style="background-color:#DDDDDD;font-size:9pt;">
<td colspan="6" align="right">
Subtotal: <cfoutput>#DollarFormat(variables.subtotal)#</cfoutput><br>
<cfif logMem.c_state EQ "FL">
Tax: <cfoutput>#DollarFormat(variables.tax)#</cfoutput>
</cfif>
Shipping:<cfoutput>#DollarFormat(variables.shipping)#</cfoutput>
<b>Order Total: <cfoutput>#DollarFormat(variables.totalprice)#</cfoutput></b></td>
</tr>
</table><p>

Total Items in Order: <cfoutput>#variables.totalItems#</cfoutput><br>
<b>Order Total: <cfoutput>#DollarFormat(variables.totalprice)#</cfoutput></b>
</cfif>
</cfif>


This page is slightly complex, but not too bad once we look into it. We start off doing some error checking. First, we check to see if the user is logged in. We don't want someone who hasn't logged in stumbling upon this page. You can use this snippet on all of the order processing pages. Then, we check to make sure we have all the credit card information we need after making a database query to get the session user information. If we don't, the user cannot move forward and process their order. If the user passes all the tests, they can then move on to the next part of the coding.

We then do a virutally identical loop to the one in our cart.cfm page. We find and display all of the products in the user's shopping cart. Next, several variables are displayed regarding the order: the subtotal, tax, shipping, and the combined total. Now, you may be wondering, where do all these variables come from? Well, if you notice the <cfinclude> tag, that is your answer. In the page ordettotals.cfm we create several variables that we need on this page and the processing page subsequent to this one. Below is the ordertotals page:

ordertotals.cfm - Order variables.
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
</cfloop>

<cfset totalprice = 0>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset totalprice = variables.totalprice + total[i]>
<cfset subtotal = variables.totalprice>
</cfloop>
<cfset shipping = variables.totalprice * .1>

<cfif logMem.c_state EQ "FL">
<cfset tax = variables.totalprice * .06>
<cfset fulltotal = variables.totalprice + variables.shipping + variables.tax>
<cfset totalprice = variables.fulltotal>
<cfelse>
<cfset fulltotal = variables.totalprice + variables.shipping>
<cfset totalprice = variables.fulltotal>
</cfif>

<cfset totalItems = 0>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset totalItems = variables.totalItems + session.shoppingcart[i].quantity>
</cfloop>

We set a few variables on this page: total price per item, total price, shipping price, tax (if applicable), and the fulltotal.

Like in our cart, we loop through to find the price of each item. Then, like before, we add up the prices to get our subtotal. Next, we figure out the shipping. Here, it is configured as 10%. This page is helpful because if you ever want to change the shipping right, the only place you have to change it is here.

A commonly disregarded item is the tax. On the Internet, the only time you ahev to charge tax is when it is an intrastate purchase (within the selling state). In this case, the homestate is Florida (make sure you use a select box in the sign up page to guarantee the state is input as "FL" to maintain consistency. In Florida, sales tax is 6%. Depending on whether or not the customer is in our home state, it sets the next 2 varibales: totalprice, and fulltotal. Full total is the total item price + the shipping price + the tax price (if necessary). You see the cfif tag is used to determine whether or not tax is to be added.

Lastly, we figure out the total items in the cart. You should recognize this code from the cart.cfm page.

Now, the last, and possibly most important part - processing the order.

processorder.cfm - Process the order.
<cfif session.allowin NEQ "True">
You must be logged in to view this area.
<cfelse>
<cfquery name="logMem" datasource="test">
SELECT *
FROM LCustomers
WHERE username = '#session.username#'
</cfquery>

<cfinclude template="ordertotals.cfm">


<!--- Insert into Orders Database --->

<cfquery name="addOrder" datasource="test">
INSERT INTO LOrders (o_cust, o_total, o_items)
VALUES ('#logMem.c_id#','#variables.totalprice#', '<cfoutput><cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i"><cfif i eq arrayLen(session.shoppingcart)>#session.shoppingcart[i].name#<cfelse>#session.shoppingcart[i].name#, </cfif></cfloop></cfoutput>')
</cfquery>


<!--- E-mail order to Administration --->

<cfmail
from="order@yoursite.com"
to="CustomerService@yoursite.com"
subject="YourSite.com - Order" type="html">
<html>
<head>
<style type="text/css">
Body, table, td {font-family:Arial;font-size:9pt;color:##000000;}
</style>
</head>
<body>
<div>Order To Be Processed</div>

<table width="350" border="0" cellpadding="3" cellspacing="0" style="border:2px solid ##DDDDDD;font-size:8pt;">
<tr style="background-color:##EFEFEF;">
<td><b>Date/Time:</b></td><td>#DateFormat(now(), 'mm/dd/yyyy')# #TimeFormat(Now(), 'hh:mm tt')#</td>
</tr>
<tr style="background-color:##FFFFFF;">
<td valign="top"><b>Customer Name</b>:</td><td>#logMem.c_fname# #logMem.c_lname#</td>
</tr>
<tr style="background-color:##EFEFEF;">
<td valign="top"><b>Address</b>:</td><td>#logMem.c_street#<br>#logMem.c_city#, #logMem.c_state# #logMem.c_zip#</td>
</tr>
<tr style="background-color:##FFFFFF;">
<td valign="top"><b>Credit Card:<br>Number:<br>CVV2:<br>Expiration:</b></td>
<td>#logMem.cc_type#<br>#logMem.cc_num#<br>#logMem.cc_verify#<br>#logMem.cc_expir_m#/#logMem.cc_expir_y#</td>
</tr>
</table><br><br>

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0" style="border:2px solid ##DDDDDD;">
<tr>
<td colspan="6" style="font-size:11pt;font-weight:bold;background-color:##DDDDDD;">Order Breakdown</td>
</tr>
<tr>
<td><b>Item</b></td><td><b>Product</b></td><td><b>Size</b></td><td><b>Unit Price</b></td><td><b>Quantity</b></td><td><b>Total</b></td>
</tr>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
<tr style="background-color:##<cfif i MOD 2>EFEFEF<cfelse>FFFFFF</cfif>;">
<td>#session.shoppingcart[i].productID#</td>
<td>#session.shoppingcart[i].name#</td>
<td>#session.shoppingcart[i].size#</td>
<td>#DollarFormat(session.shoppingcart[i].price)#</td>
<td>#session.shoppingcart[i].quantity#</td>
<td>#DollarFormat(total[i])#</td>
</tr>
</cfloop>
<tr>
<td colspan="6" style="font-size:11pt;font-weight:bold;background-color:##DDDDDD;" align="right">
<div style="font-size:9pt;">
<b>Subtotal</b>: #DollarFormat(variables.subtotal)#<br>
<cfif logMem.c_state EQ "FL">
Tax: #DollarFormat(variables.tax)#<br>
</cfif>
<b>Shipping</b>: #DollarFormat(variables.shipping)#</div>
Order Total: #DollarFormat(variables.totalprice)#</td>
</tr>
</table>
</body>
</html>
</cfmail>

<!--- E-mail order to customer --->

<cfmail
from="order@yoursite.com"
to="#logMem.c_email#"
subject="YourSite.com - Thank You for Your Order" type="html">

********SIMILAR E-MAIL BODY TO ABOVE & BELOW (DO NOT USE CFOUTPUT TAGS)********

</cfmail>

<!--- Show Order Information page to Customer --->

<div>Order Information</div>
Your order has been processed. This information has been e-mailed to <b><cfoutput query="logMem">#logMem.c_email#</cfoutput></b>.
<br>Please print this page for your records.<p>

<table width="250">
<tr>
<td valign="top"><b>Customer Name</b>:</td><td><cfoutput query="logMem">#logMem.c_fname# #logMem.c_lname#</cfoutput></td>
</tr>
<tr>
<td valign="top"><b>Address</b>:</td><td><cfoutput query="logMem">#logMem.c_street#<br>#logMem.c_city#, #logMem.c_state# #logMem.c_zip#</cfoutput></td>
</tr>
<tr>
<td valign="top"><b>Credit Card:</b></td><td><cfoutput query="logMem">#logMem.cc_type#<br>xxxx-xxxx-xxxx-#Right(logMem.cc_num,4)#</cfoutput></td>
</tr>
</table><br><br>

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0" style="border:2px solid #DDDDDD;">
<tr>
<td><b>#</b></td><td><b>Product</b></td><td><b>Size</b></td><td><b>Unit Price</b></td><td><b>Quantity</b></td><td><b>Total</b></td>
</tr>
<cfoutput>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
<tr style="background-color:##<cfif i MOD 2>EFEFEF<cfelse>FFFFFF</cfif>;">
<td>#i#</td>
<td>#session.shoppingcart[i].name#</td>
<td>#session.shoppingcart[i].size#</td>
<td>#DollarFormat(session.shoppingcart[i].price)#</td>
<td>#session.shoppingcart[i].quantity#</td>
<td>#DollarFormat(total[i])#</td>
</tr>
</cfloop>
</cfoutput>
<tr style="background-color:#DDDDDD;font-size:11pt;">
<td colspan="6" align="right">
<div style="font-size:9pt;">
Subtotal: <cfoutput>#DollarFormat(variables.subtotal)#</cfoutput><br>
<cfif logMem.c_state EQ "FL">
Tax: <cfoutput>#DollarFormat(variables.tax)#</cfoutput><br>
</cfif>
Shipping: <cfoutput>#DollarFormat(variables.shipping)#</cfoutput></div>
<b>Order Total: <cfoutput>#DollarFormat(variables.fulltotal)#</cfoutput></b></td>
</tr>
</table><br>
<div align="left">
<a href="Javascript:window.print();">Print This Page</a></div>
<cfscript>
ArrayClear(session.shoppingcart);
</cfscript>

</cfif>


Ok, that was a long one, but pretty simple, and by now, it should mostly be familiar to you. We start off by checking if the user's logged in. Then, we do our query to get all our user information and include the ordertotals.cfm page to get our variables for use again.

  <!--- Insert into Orders Database --->

<cfquery name="addOrder" datasource="test">
INSERT INTO LOrders (o_cust, o_total, o_items)
VALUES ('#logMem.c_id#','#variables.totalprice#', '<cfoutput><cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i"><cfif i eq arrayLen(session.shoppingcart)>#session.shoppingcart[i].name#<cfelse>#session.shoppingcart[i].name#, </cfif></cfloop></cfoutput>')
</cfquery>

Now we add our order into our database table. This should all be familiar to you, with perhaps the exception of the loop. We look over our shopping cart one more time. This time, we output our item names as a comma delimited list. Look closely to understand precisely how the list is created.

At this point, we just have 3 things left to do: send the e-mail to ourselves to process it, send the e-mail to our customer as confirmation, and show the order confirmation page to the customer on our site after they process their order. There is nothing new in the code with the exception of the Right() function. This simply gets the 4 last digits of the customer's credit card number and displays it to them with Xs for the first 11 digits.

Our order information table is formatted just like on the cart.cfm page and the confirmorder.cfm page. By this point, you should have that loop over our shopping cart array virtually memorized. You see we again show all of our variables back to the user and input them in our e-mails. In your e-mail to your customer, use the Right() function for the credit card, just for security.

Sending an e-mail is of course just one way to process your order. This is assuming each order is processed by hand. You can of course use all differenet kinds of processing (online merchant processing, PayPal, sending the order via FTP to another computer). No matter what you do, it's all the same concept and you can use the same output coding.

Well, that is all there is to an e-commerce system with a fully functional shopping cart. Below, you will find some supplemental coding as well as quick snippets so you can quickly refer back to this page to get those coding bits.

Section 6 - Supplemental Coding - Navigation Include

Here you can find some useful and some necessary snippets and page coding information.

The first thing is the Application.cfm page. Our whole shopping cart and user log in systems are dependent on the application and session variables, so this is our Application.cfm file:

Application.cfm - Application and session set-up.
<cfapplication name="ShopCart" clientmanagement="Yes"
sessionmanagement="Yes"
sessiontimeout="#CreateTimeSpan(0,0,15,0)#"
applicationtimeout="#CreateTimeSpan(0,2,0,0)#">

<cfparam name="session.allowin" default="false">

Easy and painless. Just a basic Application.cfm page with session management. If you need to understand this further, view Pablo's User Area tutorial.


Outputting Shopping Cart Information
<table>
<tr>
<td><b>#</b></td><td><b>Product</b></td><td><b>Size</b></td><td><b>Unit Price</b></td><td><b>Quantity</b></td><td><b>Total</b></td><td><b>Action</b></td>
</tr>
<cfoutput>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
<tr style="background-color:##<cfif i MOD 2>EFEFEF<cfelse>FFFFFF</cfif>;">
<td>#i#</td>
<td>#session.shoppingcart[i].name#</td>
<td>#session.shoppingcart[i].size#</td>
<td>#DollarFormat(session.shoppingcart[i].price)#</td>
<td>#session.shoppingcart[i].quantity#</td>
<td>#DollarFormat(total[i])#</td>
<td><a href="delete_item.cfm?id=#i#">Remove Item</a></td>
</tr>
</cfloop>
</cfoutput>
</table>

Deleting A Product from the Cart
<cfset temp = arrayDeleteAt(session.shoppingcart, #URL.id#)>

Clearing the Cart
<cfscript>
ArrayClear(session.shoppingcart);
</cfscript>

Creating Shopping Cart Array
<cfif IsDefined('session.shoppingcart') is "NO">
<cfset session.shoppingcart = arrayNew(1)>
</cfif>

Updating Quantity of Product in Cart
<cfset newitem = 0>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfif session.shoppingcart[i].productid EQ #form.id#>
<cfset session.shoppingcart[i].quantity = session.shoppingcart[i].quantity + #form.qnt#>
<cfset newitem = 1>
<cfbreak>
</cfif>
</cfloop>

Adding a New Product to the Cart
<cfset temp = arrayAppend(session.shoppingcart, structNew())>
<cfset session.shoppingcart[arrayLen(session.shoppingcart)].productID = #form.id#>
<cfset session.shoppingcart[arrayLen(session.shoppingcart)].name = #form.name#>
<cfset session.shoppingcart[arrayLen(session.shoppingcart)].quantity = #form.qnt#>
<cfset session.shoppingcart[arrayLen(session.shoppingcart)].price = #form.p#>

Getting the Total Price of 1 Item
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset total[i] = session.shoppingcart[i].price * session.shoppingcart[i].quantity>
</cfloop>

Finding the Subtotal - Price of all Items Combined
<cfset totalprice = 0>
<cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i">
<cfset totalprice = variables.totalprice + total[i]>
<cfset subtotal = variables.totalprice>
</cfloop>

Determining if Tax is Necessary and Setting it
<cfif logMem.c_state EQ "FL">
<cfset tax = variables.totalprice * .06>
<cfset fulltotal = variables.totalprice + variables.shipping + variables.tax>
<cfset totalprice = variables.fulltotal>
<cfelse>
<cfset fulltotal = variables.totalprice + variables.shipping>
<cfset totalprice = variables.fulltotal>
</cfif>

Inserting Orders into the Database
<cfquery name="addOrder" datasource="test">
INSERT INTO LOrders (o_cust, o_total, o_items)
VALUES ('#logMem.c_id#','#variables.totalprice#', '<cfoutput><cfloop from="1" to="#arrayLen(session.shoppingcart)#" index="i"><cfif i eq arrayLen(session.shoppingcart)>#session.shoppingcart[i].name#<cfelse>#session.shoppingcart[i].name#, </cfif></cfloop></cfoutput>')
</cfquery>

Determining Links Depending on Log-In Status
<cfif session.allowin NEQ "True">
<a href="https://linens9.com/account_signin.cfm"

All ColdFusion Tutorials By Author: Michael Bamberger