Chapter 25

Order Entry

by Craig Eddy


CONTENTS

Perhaps the biggest boon to the growth of the Internet, despite the complaints of many of the Internet's early pioneers, has been the advent of electronic commerce. The World Wide Web has been used for marketing purposes for a few years now. The availability of safe and accurate Web-based ordering is just now becoming a reality, however.

This chapter presents an example of a Web-based order entry application. It is written using a combination of HTML forms and VBScript code. The products available on this order form are static-that is, there is no connection to a database of available products. This makes the Web page easier to design and implement. To add such a connection requires using a server-side application to generate the HTML form and the appropriate VBScript code. This example won't delve into such detail.

The VBScript code in this order entry application performs the following functions:

This chapter begins with an overview of security as it relates to Web-based commerce such as online ordering. Then, a brief review of HTTP cookies is presented, which were discussed in Chapter 14, "Customize Your Web Page with Cookies." Finally, you'll see the example application itself.

Ensuring Secure Transactions on the Web

When you discuss the Internet, the first and most hotly debated topic to enter the conversation is the subject of security. The concerns about security on the Web are well-founded given the ease with which a hacker can use well-documented methods to steal information from machines located on or communication occurring on a computer network such as the Internet. Although security isn't required to build and run the VBScript application presented in this chapter, a brief overview of various security concerns seems appropriate.

The typical concerns when dealing with electronic commerce follow:

These three concerns and possible solutions are touched on in the following sections. Another very good source of information is the Microsoft Internet Security Framework site located at http://www.microsoft.com/intdev/security/default.htm.

Authenticating the Merchant

It is necessary to authenticate the merchant (or simply the Web site being accessed) because just about anyone these days can post a Web site and use a variety of methods to request credit card numbers or electronic cash payments. As a potential purchaser of products and services on the Web, you'd like to know that companies you're about to purchase from are who they say they are.

The current trend in merchant authentication is to use site certificates. These are issued by an agency that takes the responsibility to verify that organizations requesting the site certificates are who they say they are. Internet Explorer 3.0 supports the use of site certificates for authentication. Figure 25.1 shows a sample site certificate. Notice the small padlock at the right-hand side of the status bar. This indicates that Internet Explorer currently is viewing a secure and verified site.

Figure 25.1 : A sample site certificate for a secure Web site.

Authenticating the Purchaser

Just as you as a purchaser are concerned with the authenticity of the Web site, the merchant also wants to ensure that you are who you say you are. This is less of a concern than authenticating the merchant because the merchant almost always verifies your ability to pay before providing the product or service. Still, with the possibility of credit card fraud and possible means of counterfeiting electronic cash, merchants still want to be able to verify your identity as a purchaser at their Web sites.

Internet Explorer 3.0 supports personal certificates. These are similar to site certificates and also are issued by an agency that verifies you are, indeed, who you claim to be. Currently, personal certificates are provided by an agency named VeriSign. Its Web site provides a very good overview of personal certificates and how they are obtained and used. The URL for the page is http://digitalid.verisign.com/brw_intr.htm.

Encrypting Web Communications

Obviously, if you are willing to send credit card information across a public network like the Internet, you want to know that no one else can view that information. The same holds true for personal information such as household income. Several encryption standards currently are being debated, and some are in place within Web browsers today. Eventually, one or two standards will win out; until at least one gains general acceptance, everyday purchasing on the Web will remain a fantasy. Site certificates also play a vital role in securing the channels of communication.

Reviewing Cookies

The term cookie, when used in reference to a Web page, refers to a string of characters that is stored for the particular Web page or site. The cookie can store any type of information you want. Typically, cookies store information that identifies the user of the Web browser (name, address, and phone number) or retain some state information (when the user last accessed the page, what his personal preferences related to the page are, and so on).

Using VBScript, you can access the cookie for a page using the document.cookie property. The format of the string is variable_name=value. Multiple variable/value pairs are stored by separating the pairs with a semicolon. For example, the cookie property may evaluate to this:


LastName=Eddy;FirstName=Craig;FavoriteColor=Green

This cookie has three variables stored: LastName, FirstName, and FavoriteColor.

You set the cookie for a page by assigning a string formatted as variable_name=value to the document.cookie property. For example,


document.cookie = "FavoriteColor=Yellow"

assigns or changes the setting for the variable FavoriteColor.

Cookie variables also can be set to expire at a certain time. This is accomplished by appending the string ;expires=date/time. The cookie variable then is invalid after the date/time specified.

To remove a cookie variable, set its value to the string NULL and append an expires with a value set to some date in the past.

NOTE
Cookies are valid only if the page being accessed is stored on a Web server. This is due to the fact that cookies are actually part of the transport protocol used to communicate on the Web. If you attempt to assign a value to the cookie property for a page not located on a Web server, your script code produces a trappable runtime error.

Designing the Order Entry Form

The order entry form created in this chapter is an order form that is static. For the sake of simplicity, no attempt is made to retrieve data from a product database and assemble an order form from that data.

The products sold using this form are framed portraits of United States presidents (hey, why not?). The user will be able to order any quantity of the available portraits. Shipping and handling, as well as sales tax, are calculated by the VBScript code so that users always know exactly how much the purchase will cost them. The script code also verifies the entered phone number and ZIP code for proper formatting before submitting the form data.

Figure 25.2 shows the order entry form. The top of the form contains header information: customer name, address, and phone number. This is followed by the order form that gives the user the details about each portrait: description, cost, and shipping charge. The user enters the quantity of each portrait to be ordered, and the script code updates the various subtotals and the grand total. The shipping cost, product total cost, and grand total are displayed in a separate frame that always appears at the bottom of the browser, regardless of where the user has scrolled to on the order form.

Figure 25.2 : The order entry form displayed with Internet Explorer.

Listing 25.1 shows the HTML used to create the frames. You can type it in or copy it from the CD-ROM. Save it to a Web server directory if possible. The name is irrelevant, but you'll need to remember what it is because this is the file that you'll open with Internet Explorer when it's time to test the application.


Listing 25.1. The frame container for the order entry page.

<HTML>

<HEAD>

<TITLE>Portrait Order Form</TITLE>

</HEAD>

<BODY>

<FRAMESET FRAMEBORDER=NO ROWS="90,10">

<FRAME SCROLLING=YES SRC=25-3.htm>

<FRAME SCROLLING=NO MARGINHEIGHT=5 MARGINWIDTH=5 SRC=25-2.htm>

</FRAMESET>

</BODY>

</HTML>


This Web page makes pretty basic use of frames. The <FRAMESET> tag specifies the start of a frame definition. The FRAMEBORDER=NO specifies that there should be no borders around the frames. ROWS="90,10" specifies that the frames will be stacked vertically. The top frame will take up 90 percent of the browser's viewing area, and the bottom frame uses 10 percent.

The <FRAME SCROLLING=YES SRC=25-3.htm> tag for the first frame in the frameset specifies that the frame is to be scrollable and that a file named 25-3.htm should be used as the content for the frame.

The <FRAME SCROLLING=NO MARGINHEIGHT=5 MARGINWIDTH=5 SRC=25-2.htm> tag for the second frame in the frameset specifies that the frame is not scrollable and that a file named 25-2.htm should be used as the content for the frame. This is the bottom frame shown in Figure 25.2.

Next, Listing 25.2 shows the HTML code for the bottom frame (25-2.htm). You can type the code, use the ActiveX Control Pad to assist in inserting the Label controls, or copy the code from the accompanying CD-ROM. Save the file as 25-1.htm in the same directory as the code from Listing 25.1.


Listing 25.2. The bottom frame of the order entry page.

<HTML><HEAD><TITLE>New Page</TITLE></HEAD>

<BODY><CENTER>

    <OBJECT ID="IeLabel1" WIDTH=127 HEIGHT=27

 CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

    <PARAM NAME="_ExtentX" VALUE="3334">

    <PARAM NAME="_ExtentY" VALUE="714">

    <PARAM NAME="Caption" VALUE="Shipping Total:">

    <PARAM NAME="Angle" VALUE="0">

    <PARAM NAME="Alignment" VALUE="0">

    <PARAM NAME="Mode" VALUE="1">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="ForeColor" VALUE="#000000">

    <PARAM NAME="BackColor" VALUE="#C0C0C0">

    <PARAM NAME="FontName" VALUE="Arial">

    <PARAM NAME="FontSize" VALUE="12">

    <PARAM NAME="FontItalic" VALUE="0">

    <PARAM NAME="FontBold" VALUE="1">

    <PARAM NAME="FontUnderline" VALUE="0">

    <PARAM NAME="FontStrikeout" VALUE="0">

    <PARAM NAME="TopPoints" VALUE="0">

    <PARAM NAME="BotPoints" VALUE="0">

</OBJECT>   <OBJECT ID="lblShipTot" WIDTH=80 HEIGHT=27

 CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

    <PARAM NAME="_ExtentX" VALUE="1879">

    <PARAM NAME="_ExtentY" VALUE="714">

    <PARAM NAME="Caption" VALUE="$0.00">

    <PARAM NAME="Angle" VALUE="0">

    <PARAM NAME="Alignment" VALUE="0">

    <PARAM NAME="Mode" VALUE="1">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="ForeColor" VALUE="#000000">

    <PARAM NAME="BackColor" VALUE="#C0C0C0">

    <PARAM NAME="FontName" VALUE="Arial">

    <PARAM NAME="FontSize" VALUE="12">

    <PARAM NAME="FontItalic" VALUE="0">

    <PARAM NAME="FontBold" VALUE="0">

    <PARAM NAME="FontUnderline" VALUE="0">

    <PARAM NAME="FontStrikeout" VALUE="0">

    <PARAM NAME="TopPoints" VALUE="0">

    <PARAM NAME="BotPoints" VALUE="0">

</OBJECT>     <OBJECT ID="IeLabel2" WIDTH=93 HEIGHT=27

 CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

    <PARAM NAME="_ExtentX" VALUE="2461">

    <PARAM NAME="_ExtentY" VALUE="714">

    <PARAM NAME="Caption" VALUE="Total Cost:">

    <PARAM NAME="Angle" VALUE="0">

    <PARAM NAME="Alignment" VALUE="0">

    <PARAM NAME="Mode" VALUE="1">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="ForeColor" VALUE="#000000">

    <PARAM NAME="BackColor" VALUE="#C0C0C0">

    <PARAM NAME="FontName" VALUE="Arial">

    <PARAM NAME="FontSize" VALUE="12">

    <PARAM NAME="FontItalic" VALUE="0">

    <PARAM NAME="FontBold" VALUE="1">

    <PARAM NAME="FontUnderline" VALUE="0">

    <PARAM NAME="FontStrikeout" VALUE="0">

    <PARAM NAME="TopPoints" VALUE="0">

    <PARAM NAME="BotPoints" VALUE="0">

</OBJECT>   <OBJECT ID="lblCostTot" WIDTH=90 HEIGHT=27

     CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

        <PARAM NAME="_ExtentX" VALUE="3360">

        <PARAM NAME="_ExtentY" VALUE="423">

        <PARAM NAME="Caption" VALUE="$0.00">

        <PARAM NAME="Angle" VALUE="0">

        <PARAM NAME="Alignment" VALUE="0">

        <PARAM NAME="Mode" VALUE="1">

        <PARAM NAME="FillStyle" VALUE="0">

        <PARAM NAME="FillStyle" VALUE="0">

        <PARAM NAME="ForeColor" VALUE="#000000">

        <PARAM NAME="BackColor" VALUE="#C0C0C0">

        <PARAM NAME="FontName" VALUE="Arial">

        <PARAM NAME="FontSize" VALUE="12">

        <PARAM NAME="FontItalic" VALUE="0">

        <PARAM NAME="FontBold" VALUE="0">

        <PARAM NAME="FontUnderline" VALUE="0">

        <PARAM NAME="FontStrikeout" VALUE="0">

        <PARAM NAME="TopPoints" VALUE="0">

        <PARAM NAME="BotPoints" VALUE="0">

   </OBJECT> <OBJECT ID="IeLabel3" WIDTH=104 HEIGHT=27

 CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

    <PARAM NAME="_ExtentX" VALUE="2752">

    <PARAM NAME="_ExtentY" VALUE="714">

    <PARAM NAME="Caption" VALUE="Grand Total:">

    <PARAM NAME="Angle" VALUE="0">

    <PARAM NAME="Alignment" VALUE="0">

    <PARAM NAME="Mode" VALUE="1">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="FillStyle" VALUE="0">

    <PARAM NAME="ForeColor" VALUE="#000000">

    <PARAM NAME="BackColor" VALUE="#C0C0C0">

    <PARAM NAME="FontName" VALUE="Arial">

    <PARAM NAME="FontSize" VALUE="12">

    <PARAM NAME="FontItalic" VALUE="0">

    <PARAM NAME="FontBold" VALUE="1">

    <PARAM NAME="FontUnderline" VALUE="0">

    <PARAM NAME="FontStrikeout" VALUE="0">

    <PARAM NAME="TopPoints" VALUE="0">

    <PARAM NAME="BotPoints" VALUE="0">

</OBJECT>   <OBJECT ID="lblGrandTot" WIDTH=90 HEIGHT=27

     CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

        <PARAM NAME="_ExtentX" VALUE="3360">

        <PARAM NAME="_ExtentY" VALUE="423">

        <PARAM NAME="Caption" VALUE="$0.00">

        <PARAM NAME="Angle" VALUE="0">

        <PARAM NAME="Alignment" VALUE="0">

        <PARAM NAME="Mode" VALUE="1">

        <PARAM NAME="FillStyle" VALUE="0">

        <PARAM NAME="FillStyle" VALUE="0">

        <PARAM NAME="ForeColor" VALUE="#000000">

        <PARAM NAME="BackColor" VALUE="#C0C0C0">

        <PARAM NAME="FontName" VALUE="Arial">

        <PARAM NAME="FontSize" VALUE="12">

        <PARAM NAME="FontItalic" VALUE="0">

        <PARAM NAME="FontBold" VALUE="0">

        <PARAM NAME="FontUnderline" VALUE="0">

        <PARAM NAME="FontStrikeout" VALUE="0">

        <PARAM NAME="TopPoints" VALUE="0">

        <PARAM NAME="BotPoints" VALUE="0">

    </OBJECT></CENTER></BODY></HTML>


This HTML file is simply a set of six ActiveX Label controls. You can readily obtain these controls from the Microsoft ActiveX Control Gallery at http://www.microsoft.com if they don't already exist on your machine. Note that if you cannot guarantee that users have these controls installed on their machines, you should specify the CODEBASE property. The value of the property provides the location of where the control can be downloaded and installed.

Note that the ID properties specified as lblShipTot, lblCostTot, and lblGrandTot should not be modified without a corresponding change in 25-3.htm that sets the Caption properties for these labels. Also, you should not modify the Width or Height properties. Giving the labels different Height properties from one another makes them appear in different places on the page as opposed to in a line, as shown in Figure 25.2.

Because the HTML for the main order form is mostly VBScript code, 25-3.htm is discussed in the next section.

Creating the Order Entry Form

This section discusses the creation of the main order form. Most of the HTML file is comprised of the script code. Most of the document is contained within the HTML <FORM> container. The ACTION element specified for the form should be the URL to the back-end program that is servicing the order entry process. In my example, I've used a simple ISAPI application that simply returns the data found on the HTML form.

The document is formatted with two tables. The top of the document has a table with one row (<TR> ... </TR>) and two columns (<TD> ... </TD>). The left-hand column contains the customer information input boxes. The right-hand column only contains the Submit button. Note that this is not an HTML form input of type Submit. This is actually an ActiveX command button control. This is necessary because, after this button is clicked, the VBScript code does some data-validation work before submitting the form's data to the back-end program. If the validation checks fail, the form's Submit method is not invoked and the user is given the opportunity to correct any errors.

The top and bottom portions of the form are separated with a horizontal rule (<HR>), which is simply a line that runs horizontally across the browser window. The bottom part of the document contains another table. Each row in this table has text describing the portraits and their costs. There is also a Microsoft Forms 2.0 ActiveX text box control, a hidden HTML input box, and an ActiveX Label control for each item in the table.

The ActiveX text box enables the user to enter an integer quantity specifying how many of each portrait to purchase. VBScript code verifies that the value entered is indeed an integer. After a quantity is entered, the total for the line is calculated. This total is displayed in the ActiveX label. Then the overall totals displayed in the bottom frame are updated. You'll see this when you delve into the VBScript code in the next section.

Examining the VBScript Code

This section describes the actual script code for the order entry application. Listing 25.3 shows the HTML for 25-3.htm. This section discusses the VBScript code but not the HTML contained in Listing 25.3. Most of the HTML is fairly standard.


Listing 25.3. The main frame for the order entry page.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

<HTML><HEAD>

    <SCRIPT LANGUAGE="VBScript">

<!--

Sub window_onLoad()

Dim lstrTemp



lstrTemp = ReadVariable("FirstName")

if lstrTemp <> NOT_FOUND then Document.ORDER.FirstName.Value = lstrTemp

lstrTemp = ReadVariable("LastName")

if lstrTemp <> NOT_FOUND then Document.ORDER.LastName.Value = lstrTemp

lstrTemp = ReadVariable("Address")

if lstrTemp <> NOT_FOUND then Document.ORDER.Address.Value = lstrTemp

lstrTemp = ReadVariable("City")

if lstrTemp <> NOT_FOUND then Document.ORDER.City.Value = lstrTemp

lstrTemp = ReadVariable("State")

if lstrTemp <> NOT_FOUND then Document.ORDER.State.Value = lstrTemp

lstrTemp = ReadVariable("ZIP")

if lstrTemp <> NOT_FOUND then Document.ORDER.ZIP.Value = lstrTemp

lstrTemp = ReadVariable("Phone")

if lstrTemp <> NOT_FOUND then Document.ORDER.Phone.Value = lstrTemp



Document.ORDER.FirstName.focus()



end sub



Function ReadVariable(strVariableName)

'these five variables are used in the string manipulation

'code that finds the variable in the cookie.

Dim intLocation

Dim intNameLength

Dim intValueLength

Dim intNextSemicolon

Dim strTemp



'calculate length and location of variable name

intNameLength = Len(strVariableName)

intLocation = Instr(Document.Cookie, strVariableName)



'check for existence of variable name



If intLocation = 0 Then

    'variable not found, so it can't be read

    ReadVariable = NOT_FOUND

Else

    'get a smaller substring to work with

    strTemp = Right(Document.Cookie, Len(Document.Cookie) - intLocation + 1)



    'check to make sure we found the full string, not just a substring

    If Mid(strTemp, intNameLength + 1, 1) <> "=" Then

        'oops, only found substring, not good enough

        ReadVariable = NOT_FOUND



        'note that this will incorrectly give a not found result if and only if

        'a search for a variable whose name is a substring of a preceding

        'variable is undertaken.  For example, this will fail:

        '

        'search for: MyVar

        'cookie contains: MyVariable=2;MyVar=1

    Else

        'found full string

        intNextSemicolon = Instr(strTemp, ";")



        'if not found, then we need the last element of the cookie

        If intNextSemicolon = 0 Then intNextSemicolon = Len(strTemp) + 1



        'check for empty variable (Var1=;)

        If intNextSemicolon = (intNameLength + 2) Then

            'variable is empty

            ReadVariable = ""

        Else

            'calculate value normally

            intValueLength = intNextSemicolon - intNameLength - 2

            ReadVariable = Mid(strTemp, intNameLength + 2, intValueLength)

        End If

    End If

End If

end function



dim  NOT_FOUND

NOT_FOUND = "NOT_FOUND"



-->

    </SCRIPT>

<TITLE>Main Frame in Order Entry</TITLE ></HEAD>

<BODY>

<H3>Order Entry (all fields are required)</H3><p>

 <div align=center><center><table width=80% align=center><tr><td width=75%>

    <FORM ACTION="http://pipestream.ipctech.com/cgi-win/spitback.dll"

     METHOD="POST" NAME="ORDER">

<pre><p>First Name: <input type=text size=20 maxlength=256 name="FirstName">

 Last Name: <INPUT TYPE=text SIZE=20 NAME="LastName" maxlength=256>

<br>   Address: <INPUT TYPE=text SIZE=40 NAME="Address" maxlength=256>

      City: <INPUT TYPE=text SIZE=40 NAME="City" maxlength=256>

     State: <INPUT TYPE=text SIZE=15 NAME="State" maxlength=256> ZIP: <INPUT 

TYPE=text SIZE=10 NAME="ZIP" maxlength=10>

     Phone: <INPUT TYPE=text SIZE=20 NAME="Phone" maxlength=256></pre></td>

<td width=25%><CENTER><OBJECT ID="cmdSubmit" WIDTH=96 HEIGHT=32

     CLASSID="CLSID:D7053240-CE69-11CD-A777-00DD01143C57">

        <PARAM NAME="Caption" VALUE="Submit">

        <PARAM NAME="Size" VALUE="2540;846">

        <PARAM NAME="FontCharSet" VALUE="0">

        <PARAM NAME="FontPitchAndFamily" VALUE="2">

        <PARAM NAME="ParagraphAlign" VALUE="3">

        <PARAM NAME="FontWeight" VALUE="0">

    </OBJECT></CENTER></td>

</tr></table></center></div>

 <hr>

<div align=center><center>

<table width=60% BORDER=1>

<tr><td width=25%>Description</td><td width=25%>Cost/Shipping</td>

<td width=25%>Qty</td><td width=25%>Total</td></tr>

<tr><td width=25%>Lincoln</td><td width=25%>$24.95/$4.95</td><td width=25%>

<!-- MORE SCRIPT CODE -->

<SCRIPT LANGUAGE="VBScript">

<!--

Function GetPrice(pzQtyText, pzQtyHidden, pdPrice)

Dim lExtPrice

GetPrice = -1

If instr(pzQtyText.Text, ".") then

    pzQtyText.Text = pzQtyHidden.value

    MsgBox "Please enter a vaid integer quantity!"

    Exit Function

end if

if not(isNumeric(pzQtyText.Text)) then

    pzQtyText.Text = pzQtyHidden.value

    MsgBox "Please enter a vaid integer quantity!"

    exit function

end if

lExtPrice = pdPrice * pzQtyText.Text

pzQtyHidden.value = pzQtyText.Text

GetPrice = FormatCurrency(lExtPrice)

end function



Function FormatCurrency(ptInputValue)

Dim ltValue

ltValue = ptInputValue

if instr(ltValue,".") = 0 then

    ltValue = ltValue & ".00"

elseif instr(ltValue,".") = Len(ltValue) - 1 then

    ltValue = ltValue & "0"

end if

ltValue = "$" & ltValue

FormatCurrency = ltValue

end function



Sub UpdateTotals()

dim lTmp

lTmp = CInt(document.order.LincolnQty.Value )

lTmp = lTmp + CInt(document.order.RooseveltQty.Value)

lTmp = lTmp + CInt(document.order.ReaganQty.Value)

lTmp = lTmp * 4.95

window.parent.frames(1).lblShipTot.Caption = cstr(FormatCurrency(lTmp))



Dim lTmp2

lTmp2 = CDbl(document.order.lblLincolnExt.Caption)

lTmp2 = lTmp2 + CDbl(document.order.lblRooseveltExt.Caption)

lTmp2 = lTmp2 + CDbl(document.order.lblReaganExt.Caption)

window.parent.frames(1).lblCostTot.Caption = cstr(FormatCurrency(lTmp2))



window.parent.frames(1).lblGrandTot.Caption = cstr(FormatCurrency(lTmp + ltmp2))

end sub



Sub txtLincolnQty_Change()

Dim lExtPrice

lExtPrice = GetPrice(document.order.txtLincolnQty, document.order.LincolnQty, 24.95)

if lExtPrice = -1 then exit sub

Document.ORDER.lblLincolnExt.caption = cstr(lExtPrice)

Call UpdateTotals()

end sub



Sub txtRooseveltQty_Change()

Dim lExtPrice

lExtPrice = GetPrice(document.order.txtRooseveltQty, document.order.RooseveltQty, 22.95)

if lExtPrice = -1 then exit sub

Document.ORDER.lblRooseveltExt.caption = cstr(lExtPrice)

Call UpdateTotals()

end sub



Sub txtReaganQty_Change()

Dim lExtPrice

lExtPrice = GetPrice(document.order.txtReaganQty, document.order.ReaganQty, 14.95)

if lExtPrice = -1 then exit sub

Document.ORDER.lblReaganExt.caption = cstr(lExtPrice)

Call UpdateTotals()

end sub

-->

        </SCRIPT>

        <OBJECT ID="txtLincolnQty" WIDTH=71 HEIGHT=24

         CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

            <PARAM NAME="VariousPropertyBits" VALUE="746604571">

            <PARAM NAME="Size" VALUE="1873;635">

            <PARAM NAME="FontCharSet" VALUE="0">

            <PARAM NAME="FontPitchAndFamily" VALUE="2">

            <PARAM NAME="FontWeight" VALUE="0">

        </OBJECT>

        <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="LincolnQty" maxlength=256>

</td><td width=25%>

        <OBJECT ID="lblLincolnExt" WIDTH=83 HEIGHT=16

         CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

            <PARAM NAME="_ExtentX" VALUE="2196">

            <PARAM NAME="_ExtentY" VALUE="423">

            <PARAM NAME="Caption" VALUE="$0.00">

            <PARAM NAME="Angle" VALUE="0">

            <PARAM NAME="Alignment" VALUE="0">

            <PARAM NAME="Mode" VALUE="1">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="ForeColor" VALUE="#000000">

            <PARAM NAME="BackColor" VALUE="#C0C0C0">

            <PARAM NAME="FontName" VALUE="Arial">

            <PARAM NAME="FontSize" VALUE="12">

            <PARAM NAME="FontItalic" VALUE="0">

            <PARAM NAME="FontBold" VALUE="0">

            <PARAM NAME="FontUnderline" VALUE="0">

            <PARAM NAME="FontStrikeout" VALUE="0">

            <PARAM NAME="TopPoints" VALUE="0">

            <PARAM NAME="BotPoints" VALUE="0">

        </OBJECT>

</td></tr>

<tr><td width=25%>Roosevelt</td><td width=25%>$22.95/$4.95</td><td width=25%>

        <OBJECT ID="txtRooseveltQty" WIDTH=71 HEIGHT=24

         CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

            <PARAM NAME="VariousPropertyBits" VALUE="746604571">

            <PARAM NAME="Size" VALUE="1873;635">

            <PARAM NAME="FontCharSet" VALUE="0">

            <PARAM NAME="FontPitchAndFamily" VALUE="2">

            <PARAM NAME="FontWeight" VALUE="0">

        </OBJECT>

        <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="RooseveltQty" maxlength=256>

</td><td width=25%>

        <OBJECT ID="lblRooseveltExt" WIDTH=83 HEIGHT=16

         CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

            <PARAM NAME="_ExtentX" VALUE="2196">

            <PARAM NAME="_ExtentY" VALUE="423">

            <PARAM NAME="Caption" VALUE="$0.00">

            <PARAM NAME="Angle" VALUE="0">

            <PARAM NAME="Alignment" VALUE="0">

            <PARAM NAME="Mode" VALUE="1">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="ForeColor" VALUE="#000000">

            <PARAM NAME="BackColor" VALUE="#C0C0C0">

            <PARAM NAME="FontName" VALUE="Arial">

            <PARAM NAME="FontSize" VALUE="12">

            <PARAM NAME="FontItalic" VALUE="0">

            <PARAM NAME="FontBold" VALUE="0">

            <PARAM NAME="FontUnderline" VALUE="0">

            <PARAM NAME="FontStrikeout" VALUE="0">

            <PARAM NAME="TopPoints" VALUE="0">

            <PARAM NAME="BotPoints" VALUE="0">

        </OBJECT>

</td></tr>

<tr><td width=25%>Reagan</td><td width=25%>$14.95/$4.95</td><td width=25%>

        <OBJECT ID="txtReaganQty" WIDTH=71 HEIGHT=24

         CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

            <PARAM NAME="VariousPropertyBits" VALUE="746604571">

            <PARAM NAME="Size" VALUE="1873;635">

            <PARAM NAME="FontCharSet" VALUE="0">

            <PARAM NAME="FontPitchAndFamily" VALUE="2">

            <PARAM NAME="FontWeight" VALUE="0">

        </OBJECT>

        <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="ReaganQty" maxlength=256>

</td><td width=25%>

        <OBJECT ID="lblReaganExt" WIDTH=83 HEIGHT=16

         CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

            <PARAM NAME="_ExtentX" VALUE="2196">

            <PARAM NAME="_ExtentY" VALUE="423">

            <PARAM NAME="Caption" VALUE="$0.00">

            <PARAM NAME="Angle" VALUE="0">

            <PARAM NAME="Alignment" VALUE="0">

            <PARAM NAME="Mode" VALUE="1">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="FillStyle" VALUE="0">

            <PARAM NAME="ForeColor" VALUE="#000000">

            <PARAM NAME="BackColor" VALUE="#C0C0C0">

            <PARAM NAME="FontName" VALUE="Arial">

            <PARAM NAME="FontSize" VALUE="12">

            <PARAM NAME="FontItalic" VALUE="0">

            <PARAM NAME="FontBold" VALUE="0">

            <PARAM NAME="FontUnderline" VALUE="0">

            <PARAM NAME="FontStrikeout" VALUE="0">

            <PARAM NAME="TopPoints" VALUE="0">

            <PARAM NAME="BotPoints" VALUE="0">

        </OBJECT>

</td></tr>

</table>

</center></div>

    </FORM>

<!-- FINAL SCRIPT SECTION -->

<SCRIPT LANGUAGE="VBScript">

<!--

Sub cmdSubmit_Click()

dim lTmp

if ValidateLen(Document.Order.FirstName, "First Name") = 0 then exit sub

if ValidateLen(Document.Order.LastName, "Last Name") = 0 then exit sub

if ValidateLen(Document.Order.Address, "Address") = 0 then exit sub

if ValidateLen(Document.Order.City, "City") = 0 then exit sub

if ValidateLen(Document.Order.State, "State") = 0 then exit sub

if ValidateLen(Document.Order.ZIP, "ZIP Code") = 0 then exit sub



lTmp = (Document.ORDER.ZIP.value)

select case Len(lTmp)

case 5

     if not isnumeric(lTmp)  then

         Call ErrorOnZIP()

         exit sub

     end if



case 10

     if mid(lTmp,6,1) <> "-" then

         call ErrorOnZIP()

         exit sub

     end if

     if not IsNumeric(left(lTmp,5)) then

         Call ErrorOnZIP()

         exit sub

     end if

     if not isnumeric(right(lTmp,4)) then

         Call ErrorOnZIP()

         exit sub

     end if

case else

     Call ErrorOnZIP()

     exit sub

end select



Document.Cookie = "FirstName=" & document.order.FirstName.Value

Document.Cookie = "LastName=" & Document.Order.LastName.Value

Document.Cookie = "Address=" & Document.Order.Address.Value

Document.Cookie = "City=" & Document.Order.City.Value

Document.Cookie = "State=" & Document.Order.State.Value

Document.Cookie = "ZIP=" & Document.Order.ZIP.Value

Document.Cookie = "Phone=" & Document.Order.Phone.Value

Document.Cookie = "LastOrderDate=" & CStr(Now)



call Document.ORDER.submit()

end sub



Function ValidateLen(pzField, ptMessage)

if Len(pzField.value) = 0 then

     MsgBox ptMessage & " is required!"

     call pzField.Focus()

     ValidateLen = 0

     exit function

end if

ValidateLen = 1

end function



Sub ErrorOnZIP()

    MsgBox "ZIP Code invalid!"

    call Document.ORDER.ZIP.Select

    call Document.ORDER.ZIP.focus()

end sub

-->

    </SCRIPT>

</BODY></html>


The script code begins with the window_onLoad event. The first step of the script is to load any cookie data that exists for the order entry page. The cookie data is saved when the user clicks the Submit button. The onLoad event calls the ReadVariable() function discussed in Chapter 14. This function reads a cookie variable from the cookie property and returns the cookie's value. The cookie data then is placed into the appropriate text boxes on the form.

After the cookie data is loaded, the focus is set to the first name text box by invoking the focus() method. This is necessary because you cannot guarantee that the first name box will receive focus when the page loads. Usually, one of the ActiveX text boxes receives focus before the HTML form does.

Scrolling further down the listing, find the comment <!-- MORE SCRIPT CODE -->. This section of code is where calculations are made based on the quantities entered by the user. The first function, GetPrice(), ensures that the user entered an integer and then calculates the total price for the line on which the quantity was entered. Note the use of the IsNumeric() function. Because the Visual Basic val() function does not appear to work within VBScript, you should use IsNumeric() instead of if val(variable_name) = 0 to determine whether variable_name stores a numeric value.

Next comes the FormatCurrency() function. Because VBScript lacks the Visual Basic format$() function, you must manually format strings. The FormatCurrency() function takes a string and formats it as $#.00 would in the format$() function.

Next comes the UpdateTotals procedure. This procedure updates the ActiveX labels found in the bottom frame. The first section of code in Listing 25.3 updates the label that displays the total shipping cost. The second section updates the total cost of the portraits, not including shipping. The final line of code updates the label displaying the grand total.

Finally, the change event code is used for the three ActiveX text boxes. All three event procedures perform the same tasks. First, the GetPrice() function is called to obtain the total product cost for the current portrait. If the quantity entered was valid, the ActiveX label displaying the extended cost for the portrait (quantity multiplied by price) is updated. Finally, the UpdateTotals procedure is called to update the bottom frame.

The final section of code appears after the <!-- FINAL SCRIPT SECTION --> comment. This code is responsible for validating the data entered into the form. The validation rules follow:

WARNING
Early versions of Internet Explorer 3.0 appear to submit an HTML form whenever the user presses the Enter key, bypassing the validation code placed in the command button's Click event. If you come up with a clever way to avoid this, e-mail me at craige@pipestream. ipctech.com.

The Submit button is not an HTML form's Submit button but rather an ActiveX command button control. Clicking this button fires the cmdSubmit_click event. This event first uses a function named ValidateLen() to check the existence of data in the specified text box. If the text box is empty, a message box is displayed and the function returns a 0. The HTML form data is not submitted in this case. After all the user information boxes are validated as having data, the ZIP code field is checked to make sure that the data is in the proper format.

After all the validation checks have passed, the script updates the cookie data. The current values entered in the text boxes are stored into the cookie. The current date/time also is stored in a cookie to store the date/time of the user's last order submission.

Finally, the form's submit() method is invoked to send the form's data to the back-end process that is servicing the order entry application.

Testing the Application

After you save or copy the code for the three listings from the CD-ROM, you can test the script. If you want to use the cookie feature, you must save the files to a Web server's content directory because cookies depend on a Web server for their operation.

Load the file 25-1.htm. It should appear as in Figure 25.2. Enter information into all the user information boxes at the top of the page. Try entering some invalid ZIP codes and clicking the Submit button. If you don't receive a message box informing you that the ZIP code is invalid, check the code in the cmdSubmit_click event. Also, if you can leave a user information field blank without receiving a message box, check to make sure that the field is included in the calls to ValidateLen().

Next, try entering some quantities into the table at the bottom of the form. You should see the appropriate label captions change. Try entering a number other than an integer. A message box should appear asking you to enter an integer. If not, check the code in the GetPrice() function.

After testing the other portions and successfully submitting the form, reload the page. The user information text boxes should contain the data previously entered. If not, first check the cmdSubmit_click event to make sure that the cookie property is being set for any missing information. If everything looks fine there, check the window_onLoad event to make sure that the data is being read for the missing field. If all fields are missing, check the code in ReadVariable() and make sure that you're using the Web server to provide the page, instead of using Internet Explorer's File | Open menu to load the operating system.

Review

The example in this chapter provides the basis for a fully operational order entry Web application. The only piece you must add is the back-end application that processes the submitted data. This is another subject for another book. Web Programming with Visual Basic, published by Sams.net, is an excellent source for learning how to program back-end Web server applications using Visual Basic.