Глава 9. История заказов и профиль
Наше знакомство с пользовательским интерфейсом электронного магазина подходит к концу. В этом разделе мы рассмотрим операции с профилем и историей заказов. Эти возможности, используемые уже после оформления заказа, позволяют покупателям получить информацию о прошлых покупках.

Состояние заказа
Хочется верить, что покупатели будут снова и снова возвращаться в построенный нами магазин. Мы хотим, чтобы покупатель мог прочитать историю своих заказов вплоть до состояния самого последнего заказа. В табл. 9.1 перечислены варианты состояния, отслеживаемые для каждого заказа.
Таблица 9.1. Допустимые состояния заказов


Значение

Описание

0

Заказ был оформлен

1

Заказ выполнен и ожидает доставки

2

Заказ был отправлен покупателю. На этой стадии покупателю может быть сообщен номер транспортной накладной

При размещении заказа ему присваивается исходное состояние 0. В следующем разделе мы рассмотрим управляющие средства, предназначенные для обновления состояния заказов.
Процесс загрузки истории заказов несложен.
Сначала покупатель переходит на страницу истории заказов (ссылка Order Status), где ему предлагается ввести регистрационные данные. Если пользователь забыл свое имя и пароль, он может потребовать, чтобы пароль был отправлен по адресу электронной почты, указанному в профиле.
Если имя и пароль введены успешно, пользователь получает доступ к списку заказов и данных об их состоянии. В этом списке можно выбрать заказ и получить о нем подробную информацию.
Прежде чем переходить к истории заказов, мы рассмотрим интерфейс для работы с профилем. При помощи этого интерфейса можно загрузить и отредактировать существующий профиль.

Интерфейс работы с профилем
На панели ссылок имеется ссылка Profile, предназначенная для работы с профилем, которую мы еще не рассматривали. Когда покупатель щелкает на ссылке, на экране появляется форма для ввода проверочных данных - адреса электронной почты и пароля.
Эта форма обслуживается страницей Profile.asp. Страница начинается со стандартного заголовка, включаемого во всех остальных страницах сайта. Далее следует небольшое сообщение для пользователя.
Другая возможность - обращение к профилю в процессе оформления заказа. Если покупатель ранее уже совершал покупки на сайте и перешел на другой компьютер, он все равно сможет загрузить свой профиль.
Рис. 9.2. Пустая форма для ввода реквизитов доставки
Листинг 9.1. Profile.asp
<%@ Language=VBScript %>
<HTML>
<!--
Profile.asp - ввод регистрационных данных для загрузки профиля.
-->
<!-- #include file="include/header.asp" -->

To retrieve your profile, please enter in
your e-mail address and password.
<BR><BR>
<b><i>Note:</b></i> If you do NOT have a username or
password, upon your first purchase you will have the
option to create one.
<BR><BR>
Мы строим форму и передаем ее странице ProfileDisplay.asp. Форма состоит из двух полей, для адреса электронной почты и пароля. Страница заканчивается одновременно с формой.
Листинг 9.2. Profile.asp (продолжение)
<!-- Форма для ввода регистрационных данных -->
<form method="post" action="ProfileDisplay.asp">
<!-- Таблица, в которой пользователь вводит адрес электронной почты и пароль.
-->
<table>
<tr>
<td align="right">
E-mail:
</td>
<td>
<input type="text" name="email" value="">
</td>
</tr>
<tr>
<td align="right">
Password:
</td>
<td>
<input type="password" name="password" value="">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Submit" name="submit">
</td>
</tr>
</table>
</form>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Страница, на которой вводятся данные для доступа к профилю. Попробуем ввести неверный адрес и пароль.
Страница, отображаемая в том случае, если пользователь ввел неправильные данные. Необходимо предусмотреть возможность отправки забытого пароля по электронной почте.
Страница Email Password.asp, отправляющая пароль по электронной почте, также использует объекты CDONTS. Безопасность данных построена на том, что пароль отправляется только на адрес владельца профиля. Если кто-нибудь попытается взломать защиту сайта, чтобы прочитать чужой профиль или историю заказов, ему сначала придется получить доступ к электронной почте покупателя.
Страница начинается с подключения к базе данных. Затем мы загружаем пароль на основании адреса, введенного покупателем, при помощи стандартной встроенной команды SQL.
Листинг 9.3. EmailPassword.asp
<%@ Language=VBScript %>
<HTML>
<!--
EmailPassword.asp - Sends the password to the
address specified by the user.
-->
<!-- #include file="include/header.asp" -->
<%
' Create an ADO database connection
set dbProfile = server.createobject("adodb.connection")
' Create the record set
set rsProfile = server.CreateObject("adodb.recordset")
' Open the connection using our ODBC file DSN
dbProfile.open("filedsn=WildWillieCDs")
' Build the SQL statement to retrieve the password
sql = "select chrPassword from shopper where chrEmail = '" & _
request("email") & "'"
' Execute the statement
set rsProfile = dbProfile.Execute(sql)
' Create the CDONTS mail object
Set objNewMail = server.CreateObject("CDONTS.NewMail")
Сначала мы проверяем, существует ли профиль с введенным адресом электронной почты. Если проверка дает положительный результат, то при вызове метода Send используется формат, отличный от приведенного в предыдущей главе-в данном случае адрес, тема и основной текст сообщения задаются непосредственно при вызове Send. После отправки сообщения мы выводим небольшое подтверждающее сообщение и закрываем страницу.
Листинг 9.4. EmailPassword.asp (продолжение)
' Убедиться в существовании профиля с заданным
' адресом электронной почты
If not rsProfile.eof Then
' Отправить сообщение вызовом метода Send почтового объекта.
' При вызове передается адрес отправителя, адрес получателя,
' тема и основной текст сообщения с паролем.
objNewMail.Send "support@wildwillieinc.com", _
request("email"), _
"Wild Willie's CD Store", _
"Here is your password: " & rsProfile("chrPassword")
End If
%>
<B>Your password has been sent to your email address.</b>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Если на форме был введен правильный адрес электронной почты, сообщение будет отправлено немедленно. Обратите внимание - страница выводит подтверждение об отправке в любом случае; из соображений безопасности не следует давать пользователю информацию о том, существует ли в базе данных профиль с заданным адресом или нет.
После этого можно переходить к отображению профиля. Страница ProfileDisplay.asp начинается со стандартного заголовка. Мы открываем подключение к базе и готовимся к чтению данных.
Листинг 9.5. ProfileDisplay.asp
<%@ Language=VBScript %>
<HTML>
<!--
ProfileDisplay.asp - Displays the shoppers
profile.
-->
<!-- #include file="include/header.asp" -->
<%
' Create an ADO database connection
set dbProfile = server.createobject("adodb.connection")
' Create the record set
set rsProfile = server.CreateObject("adodb.recordset")
' Open the connection using our ODBC file DSN
dbProfile.open("filedsn=WildWillieCDs")
Необходимо учитывать, что страница может загружаться в нескольких разных ситуациях. Первый вариант - покупатель впервые регистрируется на сайте. В этом случае мы читаем адрес электронной почты и пароль из переменных переданной формы.
Во втором варианте страница загружается из-за ошибки в обновленных данных профиля, введенных покупателем. В этом случае адрес электронной почты и пароль сохраняются в сеансовых переменных для последующего чтения.
Листинг 9.6. ProfileDisplay.asp (продолжение)
' Проверить наличие параметра в URL.
' Параметры включаются в URL при возвращении покупателя
' на страницу из-за ошибок в данных профиля.
' В этом случае имя пользователя и пароль читаются
' из сеансовых переменных.
if request("check") = "1" then
' Retrieve the values
email = session("email")
password = session("password")

else
' Otherwise we retrieve the values from
' the profile form.
email = request("email")
password = request("password")
end if
Получив адрес электронной почты и пароль, можно переходить к выполнению хранимой процедуры sp_RetrieveProfile. Процедура возвращает конкретный профиль, соответствующий этим данным.
Листинг 9.7. ProfileDisplay.asp (продолжение)
' Построить команду вызова хранимой процедуры, загружающей
' профиль на основании адреса электронной почты и пароля
sql = "execute sp_RetrieveProfile '" & email & _
"', '" & password & "'"
' Выполнить команду
set rsProfile = dbProfile.Execute(sql)
Затем мы проверяем, вернула ли процедура запрошенный профиль. Если профиль отсутствует, мы строим текстовое сообщение, позволяющее запросить пароль по электронной почте.
Листинг 9.8. ProfileDisplay.asp (продолжение)
' Проверить, был ли возвращен профиль
if rsProfile.EOF then
%>
<!-- If nothing is returned then we notify the user -->
Sorry, that email and password is incorrect.
Click <a href="profile.asp">here</a> to try again.<BR><BR>
If you have forgotten your password, enter in your email
address to have your password emailed to you.<BR><BR>
<!-- Display a form that will email the password
to the user if it has been forgotten
-->
<form method="post" action="emailpassword.asp">
Email Address: <input type="text" value="" name="email"><BR><BR>
<input type="submit" value="Submit" name="submit">
</form>
<%
else
Сразу же после загрузки профиля мы присваиваем значение глобальному идентификатору покупателя. Вспомните - на странице Shipping.asp мы проверяли ряд условий, выясняя, следует ли загружать профиль покупателя. На этот раз мы хотим указать, что профиль существует, по адресные поля еще не загружались.
Листинг 9.9. ProfileDisplay.asp (продолжение)
' Задать идентификатор покупателя для последующей загрузки профиля.
session("idShopper") = rsProfile("idShopper")
' Set the profile retrieve to 0.
session("ProfileRetrieve") = "0"
%>
Данные профиля отображаются па форме. Данные формы передаются странице UpdateProfile.asp, где происходит поиск ошибок и обновление профиля.
Листинг 9.10. ProfileDisplay.asp (продолжение)
<!-- Вывести профиль. -->
<B>Edit your profile below:</b><BR><BR>
<!-- Форма для отправки измененных данных -->
<form method="post" action="UpdateProfile.asp">
Текстовые поля для ввода данных строятся так же, как и на формах для ввода реквизитов доставки и выписки счета. По умолчанию все поля заполняются существующими данными профиля.
Листинг 9.11. ProfileDisplay.asp (продолжение)
<!-- Таблица для отображения данных профиля -->
<table>
<!-- Имя -->
<tr>
<td align="right">First Name:</td>
<td>
<input type="text" value="<%=rsProfile("chrFirstName")%>"
name="chrFirstName">
</td>
</tr>
<!-- Фамилия -->
<tr>
<td align="right">Last Name:</td>
<td>
<input type="text" value="<%=rsProfile("chrLastName")%>"
name="chrLastName">
</td>
</tr>
<!-- Адрес -->
<tr>
<td align="right">Address:</td>
<td>
<input type="text" value="<%=rsProfile("chrAddress")%>"
name="chrAddress">
</td>
</tr>
<!-- Город -->
<tr>
<td align="right">City:</td>
<td>
<input type="text" value="<%=rsProfile("chrCity")%>"
name="chrCity">
</td>
</tr>
Как и прежде, в списке штатов восстанавливается ранее выбранная строка. Для этого мы проверяем текущее значение, хранящееся в базе данных, и присваиваем строку SELECTED одной из переменных, включаемых в теги строк списка.
Листинг 9.12. ProfileDisplay.asp (продолжение)
<!-- Штат -->
<tr>
<td align="right">State:</td>
<td>

<%
' Check to see which state was selected previously
' if there was an error.
if rsProfile("chrState") = "AL" then
SelAL = "Selected"
end if
if rsProfile("chrState") = "AK" then
SelAK = "Selected"
end if
if rsProfile("chrState") = "AZ" then
SelAZ = "Selected"
end if
if rsProfile("chrState") = "AR" then
SelAR = "Selected"
end if
if rsProfile("chrState") = "CA" then
SelCA = "Selected"
end if
if rsProfile("chrState") = "CT" then
SelCT = "Selected"
end if
if rsProfile("chrState") = "CO" then
SelCO = "Selected"
end if
if rsProfile("chrState") = "DC" then
SelDC = "Selected"
end if
if rsProfile("chrState") = "DE" then
SelDE = "Selected"
end if
if rsProfile("chrState") = "FL" then
SelFL = "Selected"
end if
if rsProfile("chrState") = "GA" then
SelGA = "Selected"
end if
if rsProfile("chrState") = "HI" then
SelHI = "Selected"
end if
if rsProfile("chrState") = "ID" then
SelID = "Selected"
end if
if rsProfile("chrState") = "IL" then
SelIL = "Selected"
end if
if rsProfile("chrState") = "IN" then
SelIN = "Selected"
end if
if rsProfile("chrState") = "IA" then
SelIA = "Selected"
end if
if rsProfile("chrState") = "KS" then
SelKS = "Selected"
end if
if rsProfile("chrState") = "KY" then
SelKY = "Selected"
end if
if rsProfile("chrState") = "LA" then
SelLA = "Selected"
end if
if rsProfile("chrState") = "ME" then
SelME = "Selected"
end if
if rsProfile("chrState") = "MA" then
SelMA = "Selected"
end if
if rsProfile("chrState") = "MD" then
SelMD = "Selected"
end if
if rsProfile("chrState") = "MI" then
SelMI = "Selected"
end if
if rsProfile("chrState") = "MN" then
SelMN = "Selected"
end if
if rsProfile("chrState") = "MS" then
SelMS = "Selected"
end if
if rsProfile("chrState") = "MO" then
SelMO = "Selected"
end if
if rsProfile("chrState") = "MT" then
SelMT = "Selected"
end if
if rsProfile("chrState") = "NE" then
SelNE = "Selected"
end if
if rsProfile("chrState") = "NV" then
SelNV = "Selected"
end if
if rsProfile("chrState") = "NH" then
SelNH = "Selected"
end if
if rsProfile("chrState") = "NJ" then
SelNJ = "Selected"
end if
if rsProfile("chrState") = "NM" then
SelNM = "Selected"
end if
if rsProfile("chrState") = "NY" then
SelNY = "Selected"
end if
if rsProfile("chrState") = "NC" then
SelNC = "Selected"
end if
if rsProfile("chrState") = "ND" then
SelND = "Selected"
end if
if rsProfile("chrState") = "OH" then
SelOH = "Selected"
end if
if rsProfile("chrState") = "OK" then
SelOK = "Selected"
end if
if rsProfile("chrState") = "OR" then
SelOR = "Selected"
end if
if rsProfile("chrState") = "PA" then
SelPA = "Selected"
end if
if rsProfile("chrState") = "RI" then
SelRI = "Selected"
end if
if rsProfile("chrState") = "SC" then
SelSC = "Selected"
end if
if rsProfile("chrState") = "SD" then
SelSD = "Selected"
end if
if rsProfile("chrState") = "TN" then
SelTN = "Selected"
end if
if rsProfile("chrState") = "TX" then
SelTX = "Selected"
end if
if rsProfile("chrState") = "UT" then
SelUT = "Selected"
end if
if rsProfile("chrState") = "VT" then
SelVT = "Selected"
end if
if rsProfile("chrState") = "VA" then
SelVA = "Selected"
end if
if rsProfile("chrState") = "WY" then
SelWY = "Selected"
end if
if rsProfile("chrState") = "WI" then
SelWI = "Selected"
end if
if rsProfile("chrState") = "WV" then
SelWV = "Selected"
end if
if rsProfile("chrState") = "WA" then
SelWA = "Selected"
end if
if rsProfile("chrState") = "FSO" then
SelFSO = "Selected"
end if

%>
Затем мы строим список штатов. В каждую строку списка включается значение соответствующей переменной. Переменная, которой была присвоена строка SELECTED, вставляет ключевое слово в тег.

Листинг 9.13. ProfileDisplay.asp (продолжение)
<!-- Список для выбора штата. -->
<select name="chrState">
<option value="">Select a State
<option value="AL" <%=SelAL%>>Alabama
<option value="AK" <%=SelAK%>>Alaska
<option value="AZ" <%=SelAZ%>>Arizona
<option value="AR" <%=SelAR%>>Arkansas
<option value="CA" <%=SelCA%>>California
<option value="CT" <%=SelCT%>>Connecticut
<option value="CO" <%=SelCO%>>Colorado
<option value="DC" <%=SelDC%>>D.C.
<option value="DE" <%=SelDE%>>Delaware
<option value="FL" <%=SelFL%>>Florida
<option value="GA" <%=SelGA%>>eorgia
<option value="HI" <%=SelHI%>>Hawaii
<option value="ID" <%=SelID%>>Idaho
<option value="IL" <%=SelIL%>>Illinois
<option value="IN" <%=SelIN%>>Indiana
<option value="IA" <%=SelIA%>>Iowa
<option value="KS" <%=SelKS%>>Kansas
<option value="KY" <%=SelKY%>>Kentucky
<option value="LA" <%=SelLA%>>Louisiana
<option value="ME" <%=SelME%>>Maine
<option value="MA" <%=SelMA%>>Massachusetts
<option value="MD" <%=SelMD%>>Maryland
<option value="MI" <%=SelMI%>>Michigan
<option value="MN" <%=SelMN%>>Minnesota
<option value="MS" <%=SelMS%>>Mississippi
<option value="MO" <%=SelMO%>>Missouri
<option value="MT" <%=SelMT%>>Montana
<option value="NE" <%=SelNE%>>Nebraska
<option value="NV" <%=SelNV%>>Nevada
<option value="NH" <%=SelNH%>>New Hampshire
<option value="NJ" <%=SelNJ%>>New Jersey
<option value="NM" <%=SelNM%>>New Mexico
<option value="NY" <%=SelNY%>>New York
<option value="NC" <%=SelNC%>>North Carolina
<option value="ND" <%=SelND%>>North Dakota
<option value="OH" <%=SelOH%>>Ohio
<option value="OK" <%=SelOK%>>Oklahoma
<option value="OR" <%=SelOR%>>Oregon
<option value="PA" <%=SelPA%>>Pennsylvania
<option value="RI" <%=SelRI%>>Rhode Island
<option value="SC" <%=SelSC%>>South Carolina
<option value="SD" <%=SelSD%>>South Dakota
<option value="TN" <%=SelTN%>>Tennessee
<option value="TX" <%=SelTX%>>Texas
<option value="UT" <%=SelUT%>>Utah
<option value="VT" <%=SelVT%>>Vermont
<option value="VA" <%=SelVA%>>Virginia
<option value="WA" <%=SelWA%>>Washington
<option value="WY" <%=SelWY%>>Wyoming
<option value="WI" <%=SelWI%>>Wisconsin
<option value="WV" <%=SelWV%>>West Virginia
<OPTION value="FSO" <%=SelFSO%>>Military Stuff
</select>
Как и на предыдущих формах, мы хотим, чтобы клиенты из других стран могли ввести название области. Кроме того, в списке стран восстанавливается ранее выбранная страна.
Листинг 9.14. ProfileDisplay.asp (продолжение)
<!-- Область -->
or Province:<input type="text" value="<%=rsProfile("chrProvince")%>"
name="chrProvince" size="15">

</td>
</tr>
<!-- Country -->
<tr>
<td align="right">Country:</td>
<td>

<%
' Check to see which country was selected previously
' if there was an error.
if rsProfile("chrCountry") = "US" then
SelUS = "Selected"
end if
if rsProfile("chrCountry") = "CA" then
SelCA = "Selected"
end if

if rsProfile("chrCountry") = "MX" then
SelMX = "Selected"
end if

%>
<!-- Country select box -->
<select name="chrCountry">
<option value="">Select a Country
<option value="US" <%=SelUS%>>United States
<option value="CA" <%=SelCA%>>Canada
<option value="MX" <%=SelMX%>>Mexico
</select>
</td>
</tr>
Далее следуют стандартные текстовые поля для ввода адреса.
Листинг 9.15. ProfileDisplay.asp (продолжение)
<!-- Почтовый индекс -->
<tr>
<td align="right">Zip/Postal Code:</td>
<td>
<input type="text" value="<%=rsProfile("chrZipCode")%>"
name="chrZipCode">
</td>
</tr>
<!-- Phone -->
<tr>
<td align="right">Phone:</td>
<td>
<input type="text" value="<%=rsProfile("chrPhone")%>"
name="chrPhone">
</td>
</tr>
<!-- Fax -->
<tr>
<td align="right">Fax:</td>
<td>
<input type="text" value="<%=rsProfile("chrFax")%>" name="chrFax">
</td>
</tr>
<!-- Email -->
<tr>
<td align="right">Email:</td>
<td>
<input type="text" value="<%=rsProfile("chrEmail")%>" name="chrEmail">
</td>
</tr>
Листинг 9.16. ProfileDisplay.asp (продолжение)
<!-- Password -->
<tr>
<td align="right">Password:</td>
<td>
<input type="password" value="<%=rsProfile("chrPassword")%>"
name="chrPassword")>
</td>
</tr>
<!-- Option to save the profile as a cookie -->
<tr>
<td align="right">Save Profile Cookie?:</td>
<td>

<%
' Default the cookie based on the previous selection.
if rsProfile("intCookie") = 1 then

YesChecked = "CHECKED"

else

NoChecked = "CHECKED"

end if
%>

<!-- Radio button input for defaulting a cookie
with the shopper ID -->
<input type="radio" value="1" name="intCookie" <%=YesChecked%>> Yes
<input type="radio" value="0" name="intCookie" <%=NoChecked%>> No
</td>
</tr>
Листинг 9.17. ProfileDisplay.asp (продолжение)
<!-- Submit Button -->
<tr>
<td colspan="2" align="center">
<input type="hidden" name="idShopper"
value="<%=rsProfile("idShopper")%>">
<input type="submit" value="Submit" name="Submit">
</td>
</tr>
</table>
</form>
<%
end if
%>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Листинг 9.18. Хранимая процедура sp_RetrieveProfile
/* Retrieve the profile based on email
and password */
CREATE PROCEDURE sp_RetrieveProfile
/* The email address and password
are passed in */
@email varchar(255),
@password varchar(25)
AS
/* Select the shopper data */
select * from shopper
where chrEmail = @email and
chrPassword = @Password
Листинг 9.19. UpdateProfile.asp
<%@ Language=VBScript %>
<%
' ****************************************************
' UpdateProfile.asp - обновление профиля на основании
' данных, введенных пользователем.
' ****************************************************
' Retrieve all of the data that the user entered
' by using the request object.
chrFirstName = request("chrFirstName")
chrLastName = Request("chrLastName")
chrAddress = Request("chrAddress")
chrCity = Request("chrCity")
chrState = Request("chrState")
chrProvince = Request("chrProvince")
chrCountry = Request("chrCountry")
chrZipCode = Request("chrZipCode")
chrPhone = Request("chrPhone")
chrFax = Request("chrFax")
chrEmail = Request("chrEmail")
chrPassword = Request("chrPassword")
intCookie = request("intCookie")
Затем начинается проверка данных профиля. В сущности, мы всего лишь убеждаемся в том, что поля не остались пустыми.
Листинг 9.19. UpdateProfile.asp
' Убедиться в том, что на форме было введено имя.
if chrFirstName = "" then
' Сообщить об ошибке.
strError = "You did not enter in your first name.<BR>"

end if
' Check to see if a last name was entered.
if chrLastName = "" then
strError = strError & "You did not enter in your last name.<BR>"
end if
' Check to see if an address was entered
if chrAddress = "" then
strError = strError & "You did not enter in your address.<BR>"
end if
' Check to see if a city was entered.
if chrCity = "" then
strError = strError & "You did not enter in your city.<BR>"
end if
Также необходимо проверить комбинацию страны со штатом/областью. Если в списке были выбраны США, должен быть указан штат, а если другая страна - должно быть введено название области.
Листинг 9.21. UpdateProfile.asp (продолжение)
' Check to see if the selected country is US
if chrCountry = "US" then
' Check to see if a state was entered.
if chrState = "" then
' Build the error.
strError = strError & "Invalid state<BR>"
end if
else
' If a International country then check the
' province field.
if chrProvince = "" then

' Build the error.
strError = strError & "Invalid province<BR>"

end if
end if
Также необходимо убедиться в том, что на форме была выбрана страна. После этого проверяются оставшиеся поля.
Листинг 9.22. UpdateProfile.asp (продолжение)
' Ensure a country was entered.
if chrCountry = "" then
' Build an error string.
strError = strError & "Invalid country<BR>"

end if
' Check to see if a zip code was entered.
if chrZipCode = "" then
' Build an error string.
strError = strError & "You did not enter in your zip code.<BR>"
end if
' Check to see if a zip code was entered.
if chrPhone = "" then
strError = strError & "You did not enter in your phone number.<BR>"
end if
' Check to see if a zip code was entered.
if chrEmail = "" then
strError = strError & "You did not enter in your email address.<BR>"
end if
' Check to see if a zip code was entered.
if chrPassword = "" then
strError = strError & "You did not enter in your password.<BR>"
end if
Затем мы проверяем наличие ошибок во введенных данных. При обнаружении ошибок выводится соответствующее сообщение. Чтобы страница отличалась от страниц, используемых при оформлении заказа, при выводе ошибки мы не переходим на страницу профиля.
Обратите внимание - построение всех тегов страницы происходит внутри секции вывода ошибок. Адрес электронной почты и пароль сохраняются в сеансовых переменных, и покупателю предоставляется ссылка для возвращения на страницу профиля.
Листинг 9.23. UpdateProfile.asp (продолжение)
' Now we check to see if there are any errors.
if strError <> "" then
%>
<HTML>
<!-- #include file="include/header.asp" -->
<!-- Note the error -->
<B><font color="red">
There is an error in your profile:<BR><BR>
</b></font>
<%
' Write out the error messages
Response.Write strError
' Save the email and password in session
' variables for reference on the profile
' form.
session("email") = chrEmail
session("password") = chrPassword

%>
<!-- Link back to the profile page. The check
parameter indicates the email and password
should be retrieved from session variables.
-->
<BR>
Click <a href="profiledisplay.asp?Check=1">here</a> to update.
<%
else
Если ошибок не было, мы открываем подключение к базе данных и обновляем данные профиля. Как и в предыдущих примерах, одиночные апострофы перед занесением в базу данных SQL необходимо удвоить.
Листинг 9.24. UpdateProfile.asp (продолжение)
' Создать объект подключения к базе данных
set dbProfile = server.createobject("adodb.connection")

' Открыть подключение, используя файловый DSN ODBC
dbProfile.open("filedsn=WildWillieCDs")
' Если в именах присутствуют одиночные апострофы,
' перед сохранением в базе их необходимо удвоить
chrFirstName = replace(chrFirstName, "'", "''")
chrLastName = replace(chrLastName, "'", "''")
chrAddress = replace(chrAddress, "'", "''")
chrCardName = replace(chrCardName, "'", "''")
chrCity = replace(chrCity, "'", "''")
Переданные значения передаются хранимой процедуре sp_UpdateShopper, после чего мы вызываем построенную команду SQL.
Листинг 9.25. UpdateProfile.asp (продолжение)
' Команда SQL для обновления
' профиля в базе данных
sql = "execute sp_UpdateShopper '" & _
request("chrFirstName") & "', '" & _
request("chrLastName") & "', '" & _
request("chrAddress") & "', '" & _
request("chrCity") & "', '" & _
request("chrState") & "', '" & _
request("chrProvince") & "', '" & _
request("chrCountry") & "', '" & _
request("chrZipCode") & "', '" & _
request("chrPhone") & "', '" & _
request("chrFax") & "', '" & _
request("chrEmail") & "', '" & _
request("chrPassword") & "', " & _
request("intCookie") & ", " & _
request("idShopper")
' Execute the SQL statement
dbProfile.execute(sql)
Далее мы проверяем, хочет ли пользователь создать cookie для упрощения последующей загрузки профиля. Для создания cookie используется коллекция Cookies объекта Request. Cookie сохраняется под именем WWCD. Кроме того, необходимо задать срок действия, чтобы файл cookie просуществовал в течение достаточно долгого времени.
Листинг 9.26. UpdateProfile.asp (продолжение)
' Создание cookie
if request("intCookie") = 1 then

' Store the shopper ID
Response.Cookies("WWCD") = request("idShopper")

' Expire the cookie down the road.
Response.Cookies("WWCD").Expires = "December 31, 2001"

else

' Delete the cookie
Response.Cookies("WWCD") = ""

end if
%>
В этом случае также создается полный набор страничных тегов с информацией об успешном обновлении профиля. Страница завершается стандартным набором завершающих тегов.
Листинг 9.27. UpdateProfile.asp (продолжение)
<HTML>
<!-- #include file="include/header.asp" -->
<!-- Thank the customer for the order -->
<b>Your profile has been updated!</b>
<%
end if
%>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Если проверка данных прошла успешно, внесение изменений в базу осуществляется хранимой процедурой sp_UpdateShopper. Процедура просто читает новые значения полей и при помощи команды UPDATE обновляет запись, у которой поле idShopper совпадает с переданным идентификатором.

Листинг 9.28. sp_UpdateShopper
/* Хранимая процедура для обновления данных покупателя */
CREATE PROCEDURE sp_UpdateShopper
/* Pass in the key shopper data */
@chrFirstName varchar(150),
@chrLastName varchar(150),
@chrAddress varchar(150),
@chrCity varchar(150),
@chrState varchar(150),
@chrProvince varchar(150),
@chrCountry varchar(100),
@chrZipCode varchar(50),
@chrPhone varchar(25),
@chrFax varchar(25),
@chrEmail varchar(100),
@chrPassword varchar(25),
@intCookie int,
@idShopper int
AS
/* При вызове процедуре передаются основные данные покупателя */
update shopper set
chrFirstName = @chrFirstName,
chrLastname = @chrLastName,
chrAddress = @chrAddress,
chrCity = @chrCity,
chrState = @chrState,
chrProvince = @chrProvince,
chrCountry = @chrCountry,
chrZipCode = @chrZipCode,
chrPhone = @chrPhone,
chrFax = @chrFax,
chrEmail = @chrEmail,
chrPassword = @chrPassword,
intCookie = @intCookie
where idShopper = @idShopper
Попробуем внести изменения в профиль покупателя. На рис. 9.6 показано, как выглядит сообщение об ошибке в том случае, если в профиле была неправильно указана страна.
Если проверка данных проходит успешно, происходит обновление данных профиля.
На этом наше рассмотрение операций с профилем подходит к концу. Не забывайте о различных аспектах взаимодействия с профилем в процессе оформления заказа, о которых говорилось в главе 8.

Интерфейс работы с историей заказов
Переходим к интерфейсу управления историей заказов. Этот интерфейс предназначен для того, чтобы покупатель мог вернуться на Web-сайт и получить информацию о состоянии всех своих заказов. Чтобы получить список заказов, покупатель должен прежде всего ввести свои регистрационные данные.
Страница OrderStatus.asp напоминает страницу Profile.asр. Посетитель сайта также должен ввести свой адрес электронной почты и пароль, чтобы получить доступ к истории заказов.
Страница начинается со стандартных тегов, за которыми начинается форма с полями для ввода адреса и пароля.
Листинг 9.29. OrderStatus.asp
<%@ Language=VBScript %>
<HTML>
<!--
OrderStatus.asp - Login page to retrieve order status.
-->
<!-- #include file="include/header.asp" -->
To retrieve your order history, please enter in
your e-mail address and password.
<BR><BR>

<!-- Form to post the request -->
<form method="post" action="OrderHistoryDisplay.asp" id=form1 name=form1>
<!-- Table that allows the user to enter in an email address
and password.
-->
<table>
<tr>
<td align="right">
E-mail:
</td>
<td>
<input type="text" name="email" value="">
</td>
</tr>
Обратите внимание - для ввода пароля используется поле HTML типа password. Это сделано для того, чтобы вводимый пароль не отображался на экране. Форма завершается кнопкой Submit, и на этом страница OrderStatus.asp завершается.

Листинг 9.30. OrderStatus.asp (продолжение)
<tr>
<td align="right">
Password:
</td>
<td>
<input type="password" name="password" value="">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Submit" name="submit">
</td>
</tr>
</table>
</form>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Страница OrderStatus.asp. Как упоминалось выше, функции этой страницы ограничиваются простым вводом информации о пользователе.
На странице OrderHistoryDisplay.asp выводится список всех заказов, размещенных данным покупателем, вместе с информацией об их состоянии. Страница начинается с подключения к базе данных средствами ADO для проверки введенного адреса электронной почты и пароля.
Листинг 9.31. OrderHistoryDisplay.asp
<%@ Language=VBScript %>
<%
' ****************************************************
' OrderHistoryDisplay.asp - отображение истории заказов
' конкретного покупателя.
' ****************************************************
' Создать объект подключения к базе данных
set dbProfile = server.createobject("adodb.connection")
' Создать объект набора записей
set rsProfile = server.CreateObject("adodb.recordset")
' Открыть подключение, используя файловый DSN ODBC
dbProfile.open("filedsn=WildWillieCDs")
' Прочитать параметры пользователя с формы.
email = request("email")
password = request("password")
Хранимая процедура sp_RetrieveProfile загружает профиль по адресу и паролю. Затем мы переходим к построению страницы.
Листинг 9.32. OrderHistoryDisplay.asp (продолжение)
' Построить команду вызова хранимой процедуры SQL
' для загрузки профиля на основании адреса и пароля
sql = "execute sp_RetrieveProfile '" & email & _
"', '" & password & "'"
' Загрузить набор записей
set rsProfile = dbProfile.Execute(sql)
%>
<HTML>
<!-- #include file="include/header.asp" -->
Если профиль был успешно найден, мы переходим к выводу списка заказов. Для этого открывается подключение к базе данных и выполняется хранимая процедура sp_RetrieveOrders, возвращающая информацию обо всех заказах, размещенных данным пользователем.
Листинг 9.33. OrderHistoryDisplay.asp (продолжение)
<%
' Проверить, был ли найден профиль.
if rsProfile.EOF = false then
%>
<B>Here is a list of your orders:</b><BR><BR>
<%
' Create an ADO database connection
set dbOrders = server.createobject("adodb.connection")
' Create the record set
set rsOrders = server.CreateObject("adodb.recordset")
' Open the connection using our ODBC file DSN
dbOrders.open("filedsn=WildWillieCDs")
' Build the SQL stored procedure to retrieve the
' shopper orders based on the ID of the shopper.
sql = "execute sp_RetrieveOrders " & rsProfile("idShopper")
' Retrieve the record set.
set rsOrders = dbOrders.Execute(sql)
Полученную информацию о заказах необходимо снова проверить. Всегда существует вероятность того, что покупатель с существующим профилем так и не завершил ни одного заказа, или его заказы были удалены из системы.
Далее создается таблица, в которой выводится номер, дата размещения, итоговая стоимость и состояние каждого заказа.
Листинг 9.34. OrderHistoryDisplay.asp (продолжение)
' Убедиться в наличии данных.
if not rsOrders.EOF then
%>
<!-- This table displays the list of orders -->
<Table border=1 Cellpadding=3 Cellspacing=3>
<!-- Show the order number and total -->
<tr>
<th>Order #</th><th>Date Ordered</th>
<th>Order Total</th><th>Status</th>
</tr>
Затем мы начинаем в цикле перебирать данные о заказах. Прежде всего проверяется состояние заказа, обозначенное в базе данных целым числом. Команда Select проверяет номер и выводит соответствующее текстовое сообщение. Если по какой-либо причине признак состояния не совпадает ни с одним из известных значений, клиенту предлагается обратиться в службу поддержки.
Листинг 9.35. OrderHistoryDisplay.asp (продолжение)
<%
' Loop through the orders
do until rsOrders.EOF
' Check the status of the order.
select case rsOrders("idStage")
' Case 0 is that the order has been retrieved.
case 0
status = "Order Received and to be Processed"

' Case 1 is that the order is fulfilled and ready
' for shipping.
case 1
status = "Order Fulfilled and Ready to be Shipped"

' Case 2 indicates the order has been shipped and we
' display the shipping number.
case 2
status = "Order Shipped - Confirmation#: " & _
rsOrders("chrShippingNum")

' If none of these are set then we indicate that
' customer service should be called.
case else
status = "Call Customer Service for Assistance."

end select
Мы определяем идентификатор, дату оформления и итоговую стоимость каждого заказа. Все полученные данные выводятся в одной строке таблицы. Идентификатор заказа оформляется в виде ссылки; щелкнув на ней, вы получите сводку по данному заказу.
Листинг 9.36. OrderHistoryDisplay.asp (продолжение)
' Получить идентификатор, дату и итоговую стоимость заказа.
idOrder = rsOrders("idOrder")
dtOrdered = rsOrders("dtOrdered")
intTotal = formatcurrency(rsOrders("intTotal")/100, 2)
%>
<!-- Row to display the order data. -->
<tr>
<!-- Build a link to the order receipt -->
<td align="center">
<a href="OrderReceipt.asp?
idOrder=<%=idOrder%>&idShopper=<%=rsProfile("idShopper")%>">
<%=idOrder%></a>
</td>
<!-- Show the date of the order, the total of the order
and the status.
-->
<td align="center"><%=dtOrdered%></td>
<td align="center"><%=intTotal%></td>
<td align="center"><%=status%></td>
</tr>
После этого цикл возвращается к следующей записи. На этом построение таблицы заказов завершается.
Листинг 9.37. OrderHistoryDisplay.asp (продолжение)
<%
' Move to the next row
rsOrders.MoveNext
' Loop back
Loop
%>
</table>
<%
' Else indicate no order history.
else
%>
При отсутствии данных о заказах мы сообщаем покупателю об отсутствии истории заказов. Если не удалось загрузить профиль покупателя, покупателю предлагается обратиться в службу поддержки.
В данной ситуации есть несколько вариантов. Например, покупатель может потребовать, чтобы пароль был отправлен ему по электронной почте. Также можно предложить покупателю ввести данные заново. Но, скорее всего, у покупателя возникли проблемы с загрузкой истории заказов, и ему понадобится помощь.
Страница завершается стандартным набором тегов.
Листинг 9.38. OrderHistoryDisplay.asp (продолжение)
You have no order history.
<%
end if
' Indicate no order status could be retrieved and
' customer service should be called.
else
%>
<BR><B>Sorry, we could not retrieve your order status.
Please call 1-800-555-wild for help.<BR></b>
<%
end if
%>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
При работе с данными заказов используются две хранимые процедуры. Первая из них, sp_RetrieveOrders, получает идентификатор покупателя и читает данные его заказов посредством объединения таблиц OrderData, OrderStatus и Basket.
Листинг 9.39. Хранимая процедура sp_RetrieveOrders
/* Загрузка информации о заказах покупателя */
CREATE PROCEDURE sp_RetrieveOrders
/* При вызове процедуре передается идентификатор покупателя */
@idShopper int
AS
/* Выбрать информацию о заказах данного покупателя. Для получения всех основных параметров заказа необходимо объединить таблицы OrderData, OrderStatus и Basket. */
select * from OrderData, OrderStatus, basket
where @idShopper = @idShopper and
OrderData.idOrder = OrderStatus.idOrder and
basket.idBasket = OrderData.idBasket
При загрузке данных профиля используется уже знакомая процедура sp_RetrieveProfile. Адрес электронной почты и пароль, переданные в качестве параметров, указываются в секции WHERE.
Листинг 9.40. Хранимая процедура sp_RetrieveProfile
/* Выборка профиля по адресу электронной почты и паролю */
CREATE PROCEDURE sp_RetrieveProfile
/* При вызове процедуре передается адрес электронной почты и пароль */
@email varchar(255),
@password varchar(25)
AS
/* Выборка информации о покупателе */
select * from shopper
where chrEmail = @email and
chrPassword = @Password
На рис. 9.9 показан примерный вид истории заказов. Обратите внимание -идентификатор заказа представляет собой ссылку, по которой можно перейти к выводу отчета по отдельному заказу. Кроме того, для каждого заказа выводится его текущее состояние. Мы пока не создали инструменты, позволяющие обновлять состояние заказов.
Последний фрагмент нашей головоломки - страница OrderReceipt.asp, предназначенная для вывода отчетов о заказах и связанная со ссылками на странице OrderHistoryDisplay.asp. Ее начало выглядит вполне стандартно.
Листинг 9.41. OrderReceipt.asp
<%@ Language=VBScript %>
<HTML>
<!--
OrderReceipt.asp - Displays the items in the shoppers receipt.
-->
<!-- #include file="include/header.asp" -->
Прежде всего строится заголовок отчета, содержащий адресные данные, идентификатор заказа, дату размещения и т. д. Данные загружаются хранимой процедурой sp_RetrieveReceiptHeader, которой в качестве параметров передается идентификатор покупателя и идентификатор заказа.
Листинг 9.42. OrderReceipt.asp (продолжение)
<%
' Create an ADO database connection
set dbOrderReceiptHeader = server.createobject("adodb.connection")
set rsOrderReceiptHeader = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbOrderReceiptHeader.open("filedsn=WildWillieCDs")
' Call the stored procedure to retrieve the
' receipt header.
sql = "execute sp_RetrieveReceiptHeader " & _
Request("idShopper") & ", " & _
Request("idOrder")
' Execute the SQL statement
set rsOrderReceiptHeader = dbOrderReceiptHeader.execute(sql)
%>
После этого начинается построение таблицы для вывода заголовка. Таблица состоит из двух столбцов: в первом столбце отображаются реквизиты для выписки счета, а во втором - реквизиты доставки. В самой первой строке выводится номер заказа и дата его размещения.
Листинг 9.43. OrderReceipt.asp (продолжение)
<!-- Построить таблицу для вывода заголовка -->
<table>
<!-- Row to display the order id abd
the date ordered.
-->
<tr>
<td><B>Order # <%=rsOrderReceiptHeader("idOrder")%></b></td>
<td width="75"></td>
<td><b>Order Date: <%=rsOrderReceiptHeader("dtOrdered")%></b></td>
<tr>
<!-- Blank column -->
<tr>
<td colspan="3">&nbsp;</td>
</tr>
<!-- Bill to and Ship to header -->
<tr>
<td><b>Bill To:</b></td>
<td width="75"></td>
<td><b>Ship To:</b></td>
<tr>
<!-- Shipping and Billing information -->
<tr>
<td><%Response.Write rsOrderReceiptHeader("chrBillFirstName") & _
" " & rsOrderReceiptHeader("chrBillLastName")%></td>
<td width="75"></td>
<td><%Response.write rsOrderReceiptHeader("chrShipFirstName") & _
" " & rsOrderReceiptHeader("chrShipLastName")%></td>
<tr>
<!-- Billing and shipping address. -->
<tr>
<td><%=rsOrderReceiptHeader("chrBillAddress")%></td>
<td width="75"></td>
<td><%=rsOrderReceiptHeader("chrShipAddress")%></td>
<tr>
<!-- Billing and shipping address. -->
<tr>
<td><%Response.write rsOrderReceiptHeader("chrBillCity") & _
", " & rsOrderReceiptHeader("chrBillState") & _
" " & rsOrderReceiptHeader("chrBillZipCode")%></td>
<td width="75"></td>
<td><%Response.write rsOrderReceiptHeader("chrShipCity") & ", " & _
rsOrderReceiptHeader("chrShipState") & " " & _
rsOrderReceiptHeader("chrShipZipCode")%></td>
<tr>
<!-- Billing and shipping phone. -->
<tr>
<td><%=rsOrderReceiptHeader("chrBillPhone")%></td>
<td width="75"></td>
<td><%=rsOrderReceiptHeader("chrShipPhone")%></td>
<tr>
<!-- Billing and shipping email. -->
<tr>
<td><%=rsOrderReceiptHeader("chrBillEmail")%></td>
<td width="75"></td>
<td><%=rsOrderReceiptHeader("chrShipEmail")%></td>
<tr>
</table>
Переходим к перечислению позиций заказа. Обработка и вывод этой информации организованы так же, как и при работе с корзиной.
Загрузка данных из таблицы BasketItems осуществляется хранимой процедурой sp_RetrieveReceiptItems. В качестве параметров процедуре передаются идентификаторы покупателя и заказа.
Листинг 9.44. OrderReceipt.asp (продолжение)
<%
' Create an ADO database connection
set dbOrderReceiptItems = server.createobject("adodb.connection")
set rsOrderReceiptItems = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbOrderReceiptItems.open("filedsn=WildWillieCDs")
' SQL statement to retrieve the items orders.
sql = "execute sp_RetrieveReceiptItems " & _
Request("idShopper") & ", " & _
Request("idOrder")
' Execute the SQL statement
set rsOrderReceiptItems = dbOrderReceiptItems.execute(sql)
%>
Затем начинается таблица для вывода отчета. Для каждой позиции выводится код, название, атрибуты, количество единиц, цена и стоимость.
Листинг 9.45. OrderReceipt.asp (продолжение)
<!-- Таблица для вывода содержимого корзины -->
<table border="0" cellpadding="3" cellspacing="2" width="500">
<tr><td colspan="6"><HR></td></tr>
<!-- Build the header row -->
<tr>
<th>Item Code</th>
<th>Name</th>
<th>Attributes</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
Полученные записи перебираются в цикле. При каждой итерации отображаются сведения об очередной позиции. Обратите внимание на дополнительную проверку, сопровождающую вывод атрибутов.
Листинг 9.46. OrderReceipt.asp (продолжение)
<%
' Перебрать все позиции, входящие в корзину.
do until rsOrderReceiptItems.EOF
%>
<!-- Show the row -->
<tr>
<!-- Show the product id -->
<td align="center"><%=rsOrderReceiptItems("idProduct")%></td>
<!-- Show the product name -->
<td><%=rsOrderReceiptItems("chrName")%></td>

<!-- Show the product attributes -->
<td>
<% if rsOrderReceiptItems("chrColor") <> " " then %>
<%=rsOrderReceiptItems("chrSize")%>,
<%=rsOrderReceiptItems("chrColor")%>
<% end if %>
</td>

<!-- Show the product quantity -->
<td align="center"><%=rsOrderReceiptItems("intQuantity")%></td>

<!-- Show the product price -->
<td><%=formatcurrency(rsOrderReceiptItems("intPrice")/100, 2)%></td>

<!-- Show the product total cost -->
<td align="right"><%Response.write _
formatcurrency(rsOrderReceiptItems("intPrice")/100 * rsOrderReceiptItems("intQuantity"), 2)%></td>
</tr>
<%
' Move to the next row
rsOrderReceiptItems.MoveNext
loop
%>
Переходим к построению нижней части отчета. В ней выводится общая стоимость, расходы на доставку, налог и итоговая стоимость заказа, взятые непосредственно из таблицы Basket. Каждое значение выводится в отдельном столбце таблицы. Страница завершается стандартным набором тегов.
Листинг 9.47. OrderReceipt.asp (продолжение)
<!-- Вывести пустую строку -->
<tr>
<td colspan="6"><HR></td>
</tr>
<!-- Show the sub total of the basket -->
<tr>
<td colspan="5" align="right"><b>Subtotal:</b></td>
<td align="right"><%Response.Write _
formatcurrency(rsOrderReceiptHeader("intSubtotal")/100, 2) %></td>
</tr>
<!-- Стоимость доставки -->
<tr>
<td colspan="5" align="right"><b>Shipping:</b></td>
<td align="right"><%Response.Write _
formatcurrency(rsOrderReceiptHeader("intShipping")/100, 2) %></td>
</tr>
<!-- Налог -->
<tr>
<td colspan="5" align="right"><b>Tax:</b></td>
<td align="right"><%Response.Write _
formatcurrency(rsOrderReceiptHeader("intTax")/100, 2) %></td>
</tr>
<!-- Итоговая стоимость корзины -->
<tr>
<td colspan="5" align="right"><b>Total:</b></td>
<td align="right"><%Response.Write _
formatcurrency(rsOrderReceiptHeader("intTotal")/100, 2) %></td>
</tr>
</table>
<!-- #include file="include/footer.asp" -->
</BODY>
</HTML>
Загрузка данных заказа осуществляется при помощи двух хранимых процедур. Хранимая процедура sp_RetrieveReceiptHeader читает заголовок отчета, то есть основные реквизиты, связанные с заказом. Для получения необходимых данных используется объединение таблиц OrderData и Basket.
Листинг 9.48. Хранимая процедура sp_RetrieveReceiptHeader
/* Чтение данных заголовка отчета по идентификаторам покупателя и заказа */
CREATE PROCEDURE sp_RetrieveReceiptHeader
/* Pass in the ID of the shopper and
the ID of the Order */
@idShopper int,
@idOrder int
AS
/* Select the receipt header which requires
joining the orderdata and basket tables
*/
select * from OrderData, Basket
where Orderdata.idOrder = @idOrder and
OrderData.idShopper = @idShopper and
OrderData.idBasket = Basket.idBasket
Хранимая процедура sp_RetrieveReceiptItems загружает содержимое корзины для оформленного заказа. Для получения необходимых данных используется объединение таблиц Basketltem, Basket и OrderData. Идентификаторы заказа и покупателя передаются в качестве параметров.
Листинг 9.49. Хранимая процедура sp_RetrieveReceiptItems
/* Загрузка позиций, входящих в корзину заказа */
CREATE PROCEDURE sp_RetrieveReceiptItems
/* При вызове процедуре передаются идентификаторы покупателя и заказа */
@idShopper int,
@idOrder int
AS
/* Выбрать данные из объединения таблиц basketitem */
select * from basketitem, orderdata
where orderdata.idshopper = @idShopper and
orderdata.idOrder = @idOrder and
basketitem.idbasket = orderdata.idbasket
Пример отчета показан на рис. 9.10. Основные требования к отчету - возможность вывода на печать и наглядность, а также наличие всех необходимых данных на случай возникновения каких-либо вопросов по заказу.

Итоги
На этом завершается вторая часть книги. К настоящему моменту вы должны хорошо представлять себе механизм работы электронного магазина с точки зрения покупателя.
Но это лишь часть картины. В частях III и IV рассматриваются вспомогательные инструменты, обеспечивающие нормальную работу магазина. Кроме того, мы познакомимся с некоторыми маркетинговыми средствами, благодаря которым (как хочется верить) покупатели будут проводить на сайте больше времени и тратить больше денег.

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика