| Shopping Cart/E-Commerce Tutorial |
Using Arrays & Structures -Part 3 of 3- |
| By Michael Bamberger |
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"