Часть 4. Реклама

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

В главе 14 рассматриваются возможности рекламирования определенных товаров на различных 'стадиях процесса покупки. Это позволит продвигать новые товары, проводить распродажи и т. д.

Наконец, в главе 15 исследуются способы организации распродаж в нашем магазине. При этом необходимо обеспечить такие функциональные возможности, как определение дат начала и окончания распродажи, выбор цен и т. д.

В этом разделе затронут лишь небольшой круг многочисленных творческих возможностей, используемых при проведении Web-маркетинга.

Глава 13. Вертикальные и горизонтальные связи

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

Проектирование связей между товарами

В нашей базе данных встречаются связи двух типов. Связи первого типа - горизонтальные - объединяют товары, дополняющие друг друга. В качестве примера можно привести брюки, приобретаемые в комплекте с рубашкой, или монитор, приобретаемый одновременно с компьютером.

Второй тип связи - вертикальный - призван привлечь внимание покупателя к альтернативным товарам, аналогичным по назначению тем, которые он рассматривает в данный момент, но более высокого качества или же представленным в наборе. Примером может служить 21-дюймовый монитор вместо 15-дюймового, или комплект компакт-дисков вместо одного диска.

В качестве примера построим пару связей, которые пригодятся при создании пользовательского интерфейса нашего Web-магазина. В листинге 13.1 представлены три команды SQL INSERT. Таблица состоит из трех столбцов. Первый столбец, idProductA, содержит идентификатор первого товара; второй столбец, id-ProductВ, содержит идентификатор второго товара, связанного с первым. Третий столбец, idRelationType, определяет тип связи: значение 1 соответствует горизонтальной связи, 2 - вертикальной. Конечно, один товар может участвовать как в горизонтальных, так и в вертикальных связях, и информацию об этом можно сохранить путем создания дополнительных записей в таблице RelatedProducts.

Листинг 13.1. Команды SQL для создания связей между товарами

insert into RelatedProducts(idProductA, idProductB, idRelationType)
values(9, 10, 1)

insert into RelatedProducts(idProductA, idProductB, idRelationType)
values(10, 9, 1)

insert into RelatedProducts(idProductA, idProductB, idRelationType)
values(4, 3, 2)

Построение связей

Интерфейс для работы со связями будет использоваться в двух местах. Во-первых, на странице каждого товара будет выводиться перечень сопутствующих ему товаров, объединенных с ним горизонтальными связями.

Во-вторых, когда покупатель добавляет в свою корзину какой-либо товар, объединенный вертикальными связями с другими товарами, на странице корзины появится сообщение о наличии альтернативных товаров. Этот процесс показан на рис. 13.1.

Когда в корзину покупателя добавляется товар, объединенный с другим товаром вертикальной связью, появляется ссылка на этот альтернативный товар. Если щелкнуть на ссылке, появляется подробная информация об этом товаре. Если покупатель решает заказать этот товар, то он добавляется в корзину, а предыдущий товар удаляется из нее.

Необходимо проследить за тем, чтобы при такой замене общее количество единиц товара в корзине не изменилось, то есть все удаленные товары были заменены соответствующими альтернативными товарами. Начнем с рассмотрения программного кода, управляющего выводом информации о сопутствующих товарах, объединенных с данным товаром горизонтальными связями.

Сопутствующие товары (горизонтальные связи)

Мы преобразуем страницу Product.asp таким образом, чтобы она выводила ссылки на связанные товары. Эти ссылки будут размещаться в нижней части страницы, под информацией об исходном товаре. Для этого необходимо открыть подключение к базе данных.

Для поиска сопутствующих товаров будет использоваться хранимая процедура sp_RetrieveRelatedProducts, которой при вызове передается идентификатор текущего товара. Если процедура найдет связанные товары, на странице будет построена ссылка к каждому из них.

ПРИМЕЧАНИЕ
В листинге приводится только та часть программного кода, которая связана с выводом информации о связанных товарах. Предполагается, что остальной код страницы остался без изменений.

Листинг 13.2. Product.asp

<%

' Create an ADO database connection
set dbRetrieveRelatedProducts = server.createobject("adodb.connection")

' Create a record set
set rsRetrieveRelatedProducts = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbRetrieveRelatedProducts.open("filedsn=WildWillieCDs")

' Call the appropriate stored procedure
sql = "execute sp_RetrieveRelatedProducts " & request("idProduct")

' Execute the stored procedure to retrieve
' related products.
set rsRetrieveRelatedProducts = dbRetrieveRelatedProducts.Execute(sql)

' Check to see if there are any related products for
' a cross sell.
if not rsRetrieveRelatedProducts.EOF then

%>

<B>Related Products:</B><BR><BR>

<%

end if

После получения набора записей происходит циклический перебор всех найденных товаров. На странице Product.asp строится ссылка, содержащая идентификатор товара. После приведенного фрагмента следует остальной код страницы Product.asp, описанный в главе 6.

Листинг 13.3. Product.asp (продолжение)

' Loop through the related products
do until rsRetrieveRelatedProducts.EOF

%>

<!-- Build a link to the product -->
<a href="product.asp?idProduct=
<%=rsRetrieveRelatedProducts("idProduct")%>">
<%=rsRetrieveRelatedProducts("chrProductName")%></a>

<%

' Move to the next row.
rsRetrieveRelatedProducts.MoveNext

' Loop back
loop

%>

Хранимая процедура sp_RetrieveRelatedProducts получает идентификатор того товара, который мы собираемся проверять на наличие связей. Переданный идентификатор сравнивается с содержимым столбца idProductA таблицы RelatedProducts. Обратите внимание: тип связи (в данном случае 1) задается внутри хранимой процедуры.

Листинг 13.4. Хранимая процедура sp_RetrieveRelatedProducts

/* Хранимая процедура для поиска товаров, связанных с данным */
CREATE PROCEDURE sp_RetrieveRelatedProducts

/* При вызове процедуре передается идентификатор товара */
@idProduct int

AS

/* Выборка связанных товаров. Обратите внимание: горизонтальный тип связи определяется значением 1. */
select * from relatedproducts, products
where relatedproducts.idProductb = products.idproduct and
relatedproducts.idProducta = @idProduct and
idRelationType = 1

Альтернативные товары (вертикальные связи)

Рассмотрение вертикальных связей начнется с программного кода страницы Basket.asр. При каждой итерации мы рассматриваем определенный товар в корзине и проверяем, имеются ли какие-либо альтернативные товары, объединенные с данным вертикальными связями. Если это так, то сразу же после информации о выбранном товаре на странице выводится соответствующее сообщение.

Из текста сообщения покупатель узнает, что в магазине имеется товар, который, возможно, представляет для него интерес.

Программный код вставляется в цикл перебора товаров в файле Basket, as р. Начало вставляемого фрагмента приведено в листинге 13.5. Сначала мы создаем подключение к базе данных для поиска товаров, объединенных вертикальными связями с текущим товаром, который рассматривается в данный момент.

Листинг 13.5. Basket.asp

<!-- Проверка наличия альтернативных товаров -->
<%

' Создать объект подключения к базе данных
set dbUpSell = server.createobject("adodb.connection")

' Создать объект набора записей
set rsUpSell = server.CreateObject("adodb.recordset")

' Открыть подключение, используя файловый DSN ODBC
dbUpSell.open("filedsn=WildWillieCDs")

' Построить команду вызова хранимой процедуры sp_RetrieveUpSell
' для проверки наличия вертикальных связей у данного товара.
sql = "execute sp_RetrieveUpSell " & rsBasketItem("idProduct")

' Выполнить команду SQL
set rsUpSell = dbUpSell.Execute(sql)

Если результат проверки окажется положительным, мы создаем в таблице строку, распространяющуюся на всю ее ширину. В ней выводится стандартный текст, свидетельствующий о наличии альтернативного товара.

Затем мы создаем ссылку на страницу UpgradeProduct.asp, на которой можно будет заказать этот товар (см. листинг 13.6).

СОВЕТ
Возможно, для каждой связи в базе данных следует сохранить отдельное сообщение с рекламой альтернативного товара - это позволит выбрать наиболее подходящий текст для каждой из вертикальных связей.

Листинг 13.6. Basket.asp (продолжение)

' Сообщить покупателю о существовании альтернативного товара.
if rsUpSell.EOF <> true then

%>

<!-- Build a row to show the message -->
<tr>
<td></td>
<td colspan="6">
<!-- Build a link ot the UpgradeProduct.asp page -->
<b>Why not try buying
<a href="UpgradeProduct.asp?intQuantity=<%=rsBasketItem("intQuantity")%>
&idBasketItem=<%=rsBasketItem("idBasketItem")%>

&idProduct=<%=rsUpSell("idProduct")%>"><%=rsUpSell("chrProductName")%></a>
instead?</b>
</td>
</tr>

<%

end if

' Move to the next row
rsBasketItem.MoveNext

' Loop back
loop
%>

Для загрузки информации об альтернативных товарах используется хранимая процедура sp_RetrieveUpSell (см. листинг 13.7). Переданный ей идентификатор товара сравнивается с содержимым столбца idProductA таблицы RelatedProducts. На этот раз ищутся записи с типом связи 2 (вертикальная связь).

ПРИМЕЧАНИЕ
В данном примере типы связи 1 и 2 жестко программируются в двух разных, хотя и очень похожих, хранимых процедурах. Такое решение обеспечивает максимальную свободу при изменении типов связи в базе данных.

Листинг 13.7. Хранимая процедура sp_RetrieveUpSell

/* Хранимая процедура для поиска альтернативных товаров */
CREATE PROCEDURE sp_RetrieveUpSell

/* При вызове процедуре передается идентификатор товара */
@idProduct int

AS

/* Выборка записей альтернативных товаров. Вертикальный тип связи обозначается типом 2, а значение 1 соответствует горизонтальному типу. */
select * from relatedproducts, products
where products.idproduct = relatedproducts.idproductb and
relatedproducts.idProducta = @idProduct and
idRelationType = 2

Далее мы переходим к странице UpgradeProduct.asp, предназначенной для демонстрации альтернативного товара. Хотя эта страница и похожа на страницу Product.asp, все же между ними имеются существенные различия. Страница UpgradeProduct.asp начинается с включения стандартных заголовочных файлов.

Затем мы открываем подключение к базе данных для поиска информации о товарах. Искомые данные загружаются из базы хранимой процедурой sp_RetrieveProduct (см. листинг 13.8).

Листинг 13.8. UpgradeProduct.asp

<%@ Language=VBScript %>
<HTML>
<!--
UpgradeProduct.asp - This page allows the user to upgrade
the product they have purchased. It is linked to from the
shopping basket.
-->

<!-- #include file="include/header.asp" -->

<%

' Create an ADO database connection
set dbProduct = server.createobject("adodb.connection")

' Create a record set
set rsProduct = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbProduct.open("filedsn=WildWillieCDs")

' Call the Retrieve Product stored procedure to get
' the product data.
sql = "execute sp_RetrieveProduct " & request("idProduct")

' Execute the SQL statement
set rsProduct = dbProduct.Execute(sql)

' Retrieve the description, product image and
' product name.
txtDescription = rsProduct("txtDescription")
chrProductImage = rsProduct("chrProductImage")
chrProductName = rsProduct("chrProductName")
%>

Далее мы создаем форму для добавления товара в корзину. Заметим, что форма передает данные странице AddUpgradeItem.asp, а не AddItem.asp, в отличие от страницы с обычным заказом.

Страница выводит стандартную информацию об альтернативном товаре. Количество единиц текущего товара в корзине передается в URL; это значение по умолчанию присваивается соответствующему параметру альтернативного товара. Также следует учитывать, что идентификатор товара, помещенного в корзину, хранится в скрытом поле, поэтому мы сможем удалить его из корзины, если будет заказан альтернативный товар.

Страница завершается стандартным образом - выводом атрибутов товаров, включением заголовочного файла Footer.asp и т. д. (см. листинг 13.9).

Листинг 13.9. UpgradeProduct.asp (продолжение)

<!-- Form to post the upgrade request -->
<form method="post" action="addupgradeitem.asp" id=form1 name=form1>

<!-- Table to display the product information -->
<table border="0" cellpadding="3" cellspacing="3">

<!-- Show the product image, name and description. -->
<TR>
<td><img src="images/products/<%=chrProductImage%>"></td>
<td valign="top">
<CENTER><b><font size="5">
<%=chrProductName%></font></b>
</center><BR><BR>
<%=txtDescription%><BR><BR>
</td>
</TR>

<!-- Show the price -->
<TR>
<TD align="center">
<B>Price:
<%=formatcurrency(rsProduct("intPrice")/100, 2)%></b>
</td>

<TD align="center">
<!-- Show the quantity of items already selected for the other product. -->
<B>Quantity: <input type="text"
value="<%=request("intQuantity")%>" name="quantity" size="2"></b>

<!-- Hidden variables to keep the product information -->
<input type="hidden"
value="<%=request("idProduct")%>" name="idProduct">

<input type="hidden"
value="<%=rsProduct("chrProductName")%>" name="ProductName">

<input type="hidden"
value="<%=rsProduct("intPrice")%>" name="ProductPrice">

<!-- Pass along the basket item to indicate which
product is to be upgraded. -->
<input type="hidden" value="<%=request("idBasketItem")%>"
name="idBasketItem">

</td>
</TR>

<%

' Create an ADO database connection
set dbAttributes = server.createobject("adodb.connection")

' Create a record set
set rsAttributes = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbAttributes.open("filedsn=WildWillieCDs")

' Call the stored procedure to retrieve the
' product attributes.
sql = "execute sp_Attributes " & request("idProduct")

' Execute the SQL statement
set rsAttributes = dbProduct.Execute(sql)

' Check to see if attributes should be displayed
if not rsAttributes.EOF then

%>

<!-- Display the color and size attributes. -->
<TR>
<TD>
<!-- Display the color attributes -->
Color:
<SELECT name="color">

<%

' Loop through the attributes
do until rsAttributes.EOF

%>

<!-- Show the color options -->
<option value="<%=rsAttributes("chrAttributeName")%>">
<%=rsAttributes("chrAttributeName")%>

<%

' Check to see if we have reached the end of the
' attributes category.
if rsAttributes("chrCategoryName") <> "Color" then

' Exit the do loop
exit do

end if

' Move to the next row.
rsAttributes.MoveNext

loop

%>

</select>

</TD>
<TD>
<!-- Display the size attributes -->
Size:
<SELECT name="color">

<%

' Loop through the attributes.
do until rsAttributes.EOF

%>

<!-- Option to display the attribute. -->
<option value="<%=rsAttributes("chrAttributeName")%>">
<%=rsAttributes("chrAttributeName")%>

<%

' Move to the next row.
rsAttributes.MoveNext

' Loop back.
loop

%>

</select>

</TD>

</TR>

<%

end if

%>

<!-- Show the submit button -->
<TR>
<td colspan="2" align="center">
<input type="submit" value="Order" name="Submit">
</td>
</tr>

</table>

</form>

<!-- #include file="include/footer.asp" -->

</BODY>
</HTML>

Когда покупатель выбирает товар, чтобы добавить его в корзину, происходит обращение к странице Addllpgradeltem.asp. Эта страница, как и AddItem.asp, добавляет товар в корзину, но при этом она еще и удаляет из корзины исходный товар.

Прежде всего страница проверяет то, что количество заказанных товаров не равно 0. Затем из полей формы читаются различные параметры (цена, размер, цвет) того товара, который добавляется в корзину (см. листинг 13.10).

Листинг 13.10. AddUpgradeItem.asp

<%@ Language=VBScript %>
<%

' ****************************************************
' AddUpgradeItem.asp - This page will upgrade an item
' in the basket to the up-sell item.
' ****************************************************

' Check to ensure a quantity was set.
if request("quantity") = "0" then

' Send the user back to the upgrade page.
Response.Redirect("upgradeproduct.asp?idProduct=" & _
request("idProduct"))

end if

' Get the product values
intQuantity = request("quantity")
idProduct = request("idProduct")
chrName = replace(request("productname"), "'", "''")
intPrice = request("productprice")
chrSize = request("size")
chrColor = request("color")

Для включения товара в корзину используется хранимая процедура sp_InsertBasketItem. После вызова этой процедуры все готово к удалению исходного товара из корзины.

Эта задача решается при помощи хранимой процедуры sp_RemoveBasketItem. При вызове процедуре передается идентификатор исходного товара, удаляемого из корзины, после чего пользователь возвращается на страницу Basket.asp (см. листинг 13.11).

Листинг 13.11. AddUpgradeItem.asp (продолжение)

' Create an ADO database connection
set dbBasketItem = server.createobject("adodb.connection")

' Create a record set
set rsBasketItem = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbBasketItem.open("filedsn=WildWillieCDs")

' Call the appropriate stored procedure to insert
' the new item.
sql = "execute sp_InsertBasketItem " & _
session("idBasket") & ", " & _
intQuantity & ", " & _
intPrice & ", '" & _
chrName & "', " & _
idProduct & ", '" & _
chrSize & "', '" & _
chrColor & "'"

' Execute the SQL statement
set rsBasketItem = dbBasketItem.Execute(sql)


' Call the stored procedure to remove an item from the basket
' Note the id of the basket item is utilzed
sql = "execute sp_RemoveBasketItem " & _
session("idBasket") & ", " & _
request("idBasketItem")

' Execute the SQL statement
dbBasketItem.Execute(sql)

' Send the user to the basket
Response.Redirect "basket.asp"

%>

На этом мы заканчиваем разговор о программировании пользовательского интерфейса. Давайте теперь посмотрим, как все это действует. Страницу товара под названием "T-Shirt Rip" (рваная футболка). В нижней части страницы расположены ссылки на товары, так или иначе связанные с этим. В данном случае это майка, которая одевается под футболку (Undershirt).

Корзина с сообщением о наличии альтернативного товара. Чтобы получить это сообщение, включите в корзину товар Circle Sax. Затем выберите товар Candle Sticks are Falling и добавьте его в корзину.

Страница с корзиной, в которой исходный товар заменен альтернативным. При этом магазин получает больше денег, а покупатель находит товар лучшего качества!

Управление связями

Помимо пользовательского интерфейса, нам потребуется механизм управления связями между товарами. Здесь возможны два различных подхода. Во-первых, можно создать отдельный интерфейс управления для выбора пары товаров и установки связи между ними. В этом случае мы получим систему управления, основными элементами которой являются связи.

Также можно сконструировать систему управления, в которой основными элементами являются сами товары. При этом каждому товару может соответствовать несколько различных связей. В приведенных ниже примерах используется именно этот подход. Конечно, ничто не мешает применить оба подхода одновременно.

Для работы вспомогательных средств управления необходимо отредактировать файл ManageProduct.asp. Возможность добавления, обновления и удаления связей будет обеспечиваться дополнительным кодом, который мы вставим в этот файл.

СОВЕТ
Начнем с отображения существующих связей. Для каждой связи необходимо вывести названия и идентификаторы обоих товаров, а также тип связи, существующей между ними. Таким образом, для поиска и отображения существующих связей мы открываем подключение ADO к базе данных и создаем новый столбец для удаления существующих связей (см. листинг 13.12).

Листинг 13.12. ManageProduct.asp

<HR>

<table border="1" cellpadding="3" cellspacing="3">

<tr>
<th>ID</th>
<th>Related<BR>Product ID</th>
<th>Related<BR>Product</th>
<th>Relation<BR>Type</th>
<th>Delete</th>
</tr>
<%

' Create an ADO database connection
set dbRelated = server.createobject("adodb.connection")

' Create a record set
set rsRelated = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbRelated.open("filedsn=WildWillieCDs")

' Execute the stored procedure to retrieve the
' related products.
sql = "execute sp_RetrieveProductRelations " & _
request("idProduct")

' Execute the SQL statement
set rsRelated = dbRelated.Execute(sql)

' Loop through the related products
do until rsRelated.EOF

%>

<!-- Build each row to display the related
product information and an option to
delete the product. -->
<tr>
<td><%=rsRelated("idRelatedProduct")%></td>
<td><%=rsRelated("idProductB")%></td>
<td><%=rsRelated("chrProductName")%></td>
<td><%=rsRelated("idRelationType")%></td>
<td><a href="DeleteRelated.asp?idProduct=<%=request("idProduct")%>&idRelatedProduct=
<%=rsRelated("idRelatedProduct")%>">
Delete</a></td>
</tr>

<%

' Move to the next row
rsRelated.MoveNext

' Loop back
Loop

%>

</table>

<BR><BR>

Затем мы выводим список имеющихся в наличии товаров. Из этого списка можно выбрать какой-нибудь товар и построить связь между ним и другими товарами. Все сведения о товарах, полученные из базы данных, выводятся в поле списка.

Передача данных о связи странице AddRelation.asp, предназначенной для сохранения связи в базе данных, осуществляется при помощи формы. Для выбора типа связи на форме создаются кнопки-переключатели (см. листинг 13.13).

Листинг 13.13. ManageProduct.asp (продолжение)

<%

' Create an ADO database connection
set dbProducts = server.createobject("adodb.connection")

' Create a record set
set rsProducts = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbProducts.open("filedsn=WildWillieCDs")

' Execute the stored procedure to retrieve the
' current list of products
sql = "execute sp_RetrieveProducts"

' Execute the SQL statement
set rsProducts = dbProducts.Execute(sql)

%>

<!-- Build a form to post the new relation
to the database. The form will post to
AddRelation.asp. -->
<form method="post" action="AddRelation.asp">

<!-- Build a hidden variable so the posting page
knows what product to relate this product to.
-->
<input type="hidden" name="idProductA"
value="<%=request("idProduct")%>">

<!-- Select box for the products to relate to
this product. -->
<select name="idProductB">

<%
' Loop through the products
do until rsProducts.EOF
%>

<!-- Build the option value -->
<option value="<%=rsProducts("idProduct")%>">
<%=rsProducts("chrProductName")%>

<%

' Move to the next row
rsProducts.MoveNext

' Loop back
Loop

%>
</select>

<BR><BR>

<!-- Radio buttons to indicate the type of
relationship. -->
<input type="Radio" value="1"
name="RelationType">1 - Related Products

<input type="Radio" value="2"
name="RelationType">2 - Up Sell

<BR><BR>

<!-- Submit button for the form. -->
<input type="Submit" name="Submit" value="Add Relation">

</form>

Хранимая процедура sp_RetrieveProductRelations (см. листинг 13.14) загружает все ранее определенные связи заданного товара.

Листинг 13.14. Хранимая процедура sp_RetrieveProductRelations

CREATE PROCEDURE sp_RetrieveProductRelations

@idProduct int

AS

select * from relatedproducts, products
where idProductA = @idProduct and
products.idProduct = relatedproducts.idProductb

Для поиска информации обо всех товарах в базе данных хранимая процедура sp_RetrieveProducts использует команду SQL SELECT (см. листинг 13.15).

Листинг 13.15. Хранимая процедура sp_RetrieveProducts

CREATE PROCEDURE sp_RetrieveProducts AS
select * from products

Переходим к созданию новых связей. В листинге 13.16 приведен код страницы AddRelation.asp, управляющей этим процессом. Идентификатор исходного товара и того, который с ним связывается, а также идентификатор типа связи эта страница получает из присланной формы.

Для сохранения в базе данных информации о новой связи вызывается хранимая процедура sp_InsertProductRelation. После вызова процедуры пользователь направляется на страницу ManageProduct.asp для продолжения редактирования.

Листинг 13.16. AddRelation.asp

<%@ Language=VBScript %>
<%

' Создать объект подключения к базе данных
set dbProdRelation = server.createobject("adodb.connection")

' Создать объект набора записей
set rsProdRelation = server.CreateObject("adodb.recordset")

' Открыть подключение, используя файловый DSN ODBC
dbProdRelation.open("filedsn=WildWillieCDs")

' Построить команду вызова хранимой процедуры для
' сохранения связи в таблице RelatedProducts.
sql = "execute sp_InsertProductRelation " & _
request("idProductA") & ", " & _
request("idProductB") & ", " & _
request("RelationType")

' Выполнить команду SQL
set rsProdRelation = dbProdRelation.Execute(sql)

Response.Redirect "ManageProduct.asp?idProduct=" & _
request("idProductA")

%>

SQL-код создания связей между товарами, рассмотренный в начале этой главы, был инкапсулирован в хранимой процедуре sp_InsertProductRelation. При вызове ей передаются идентификаторы обоих товаров и тип связи между ними (см. листинг 13.17).

Листинг 13.17. Хранимая процедура sp_InsertProductRelation

CREATE PROCEDURE sp_InsertProductRelation

@idProductA int,
@idProductB int,
@RelationType int

AS

insert into RelatedProducts(idProductA, idProductB, idRelationType)
values(@idProductA, @idProductB, @RelationType)

Перейдем к рассмотрению страницы DeleteRelation.asp (см. листинг 13.18), предназначенной для удаления существующих связей. Идентификатор удаляемой связи передается в URL.

Для удаления связи используется хранимая процедура sp_DeleteProductRelation. После удаления пользователь направляется на страницу ManageProduct.asp для продолжения редактирования.

Листинг 13.18. DeleteRelated.asp

<%@ Language=VBScript %>
<%

' Создать объект подключения к базе данных
set dbDelProdRelation = server.createobject("adodb.connection")

' Создать объект набора записей
set rsDelProdRelation = server.CreateObject("adodb.recordset")

' Открыть подключение, используя файловый DSN ODBC
dbDelProdRelation.open("filedsn=WildWillieCDs")

' Построить команду вызова хранимой процедуры
' для удаления связи из базы данных.
sql = "execute sp_DeleteProductRelation " & _
request("idRelatedProduct")

' Выполнить команду SQL
set rsDelProdRelation = dbDelProdRelation.Execute(sql)

' Направить пользователя на страницу ManageProduct.asp
Response.Redirect "ManageProduct.asp?idProduct=" & _
request("idProduct")

%>

Последний фрагмент кода, описанный в этой главе, представлен в листинге 13.19. Хранимая процедура sp_DeleteProductRelation удаляет из базы данных запись об указанной связи.

Листинг 13.19. Хранимая процедура sp_DeleteProductRelation

CREATE PROCEDURE sp_DeleteProductRelation

@idRelatedProduct int

AS

delete from RelatedProducts where
idRelatedProduct = @idRelatedProduct

Настало время проверить интерфейс управления в действии. Список связанных товаров для товара Circle Sax. Обратите внимание на наличие двух связей.

Итоги

На этом завершается наше знакомство с горизонтальными и вертикальными связями - двумя основными маркетинговыми элементами, предназначенными для демонстрации товаров, которые могут заинтересовать покупателя. Существуют и другие варианты реализации пользовательского интерфейса и интерфейса управления, здесь же представлена лишь базовая модель, на основе которой можно построить все необходимые функции.

В следующей главе мы познакомимся с тем, как организовать вывод рекламы товаров в нашем магазине. При этом будут рассмотрены некоторые дополнительные средства, привлекающие внимание покупателя к определенным товарам.

Глава 14. Ключевые товары

Б предыдущей главе были описаны некоторые способы продвижения товаров на рынок за счет связывания их с другими товарами. В этой главе рассматриваются различные способы продвижения ключевых товаров, специально выделенных для рекламных кампаний. В обычных магазинах такие товары обычно выставляются на отдельных полках, расположенных на виду у покупателей.

Проектирование ключевых товаров на уровне базы данных

В нашем магазине информация о ключевых товарах будет выводиться в трех местах, начиная с домашней страницы Default.asр. До настоящего момента эта страница выглядела слабовато. На ней не было ничего, кроме приветственного сообщения и навигационных ссылок.

Кроме того, под панелью ссылок остается немного свободного места, которое тоже можно выделить под рекламу. В результате покупатель сможет купить ключевые товары в любой момент, не прибегая к средствам поиска.

Наконец, реклама товаров будет выводиться и в корзине покупателя. При этом нет смысла рекламировать товары, уже включенные в корзину, поэтому страница должна ограничивать рекламу лишь теми товарами, которые еще не были приобретены покупателем.

Для работы с ключевыми товарами в таблице Products создаются три новых поля. Краткие описания этих полей приведены в табл. 14.1.

Таблица 14.1. Поля, относящиеся к ключевым товарам
Поле
Описание
IntFeatured Флаг показывает, является ли данный товар ключевым
DtFeatureStart Дата начала рекламной кампании
DtFeatureEnd Дата завершения рекламной кампании

В листинге 14.1 приведены примеры команд SQL, создающих рекламируемые товары. В качестве начальной даты рекламной кампании выбирается текущая дата, а завершение рекламной кампании намечается на 1 января 2001 года.

Листинг 14.1. Команды SQL для создания рекламируемых товаров

update products set intFeatured = 1, dtFeatureStart = getdate(),
dtFeatureEnd = "1/1/2001" where idproduct = 1

update products set intFeatured = 1, dtFeatureStart = getdate(),
dtFeatureEnd = "1/1/2001" where idproduct = 2

Программирование пользовательского интерфейса

Начнем с домашней страницы Default.asр. Информация о рекламируемых товарах будет выводиться непосредственно под текстом приветственного сообщения.

Новый фрагмент, включаемый в страницу Default.asp, приведен в листинге 14.2. Сначала мы выводим информацию о наличии рекламируемых товаров, а затем открываем подключение к базе данных. Список ключевых товаров, определенных в базе в настоящий момент, загружается хранимой процедурой sp_RetrieveFeaturedProducts.

Листинг 14.2. Default.asp

<!-- Show the featured products for today. -->
<b>On sale Today!</b><BR><BR>

<%

' Create an ADO database connection
set dbSaleProd = server.createobject("adodb.connection")

' Create a record set
set rsSaleProd = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbSaleProd.open("filedsn=WildWillieCDs")

' Retrieve all of the current sale products
sql = "execute sp_RetrieveSaleProducts"

' Execute the SQL statement
set rsSaleProd = dbSaleProd.Execute(sql)

Загрузив информацию о рекламируемых товарах, мы в цикле перебираем и выводим их (см. листинг 14.3). При каждой итерации выводится название, графическое изображение и идентификатор товара.

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

Листинг 14.3. Default.asp (продолжение)

' Loop through the products
do until rsFeaturedProd.EOF

' Retrieve the product information to be displayed.
chrProductName = rsFeaturedProd("chrProductName")
chrProductImage = rsFeaturedProd("chrProductImage")
idProduct = rsFeaturedProd("idProduct")

' Check the display flag. We will rotate the
' product images from left to right.
If flag = 0 then

' Set the flag
flag = 1

%>

<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<img src="images/products/sm_<%=chrProductImage%>"
align="middle" border="0">
<%=chrProductName%></a><BR><BR>

<% else %>

<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<%=chrProductName%>
<img src="images/products/sm_<%=chrProductImage%>"
align="middle" border="0"></a><BR><BR>
<%

' Reset the flag
Flag = 0

end if

' Move to the next record
rsFeaturedProd.MoveNext

' Loop back
Loop

%>

Хранимая процедура sp_RetrieveFeaturedProducts загружает из базы данных информацию обо всех ключевых товарах, активных в данный момент (см. листинг 14.4). Текущая дата сравнивается с начальной и конечной датой рекламной кампании.

Листинг 14.4. Хранимая процедура sp_RetrieveFeaturedProducts

CREATE PROCEDURE sp_RetrieveFeaturedProducts AS

select * from products where intFeatured = 1 and
getdate() >= dtFeatureStart and getdate() <= dtFeatureEnd

На этом заканчиваются изменения, вносимые в страницу Default.asр. Переходим к модификации страницы Basket.asp (см. листинг 14.5).

Новый фрагмент начинается с открытия подключения к базе данных и вызова хранимой процедуры sp_RetrieveNonPurchFeatureProd. Процедура возвращает информацию обо всех ключевых товарах, которые еще не были включены в корзину покупателя.

Листинг 14.5. Basket.asp

<%

' Create an ADO database connection
set dbFeaturedProd = server.createobject("adodb.connection")

' Create a record set
set rsFeaturedProd = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbFeaturedProd.open("filedsn=WildWillieCDs")

' Execute the sp_RetrieveNonPurchFeatureProd stored procedure
' which will return any featured products not currently in the
' basket.
sql = "execute sp_RetrieveNonPurchFeatureProd " & session("idBasket")

' Execute the SQL statement
set rsFeaturedProd = dbFeaturedProd.Execute(sql)

Затем мы проверяем, была ли обнаружена хоть одна запись ключевого товара, отсутствующего в корзине (см. листинг 14.6). Если процедура вернула записи товаров, выводится сообщение, привлекающее внимание покупателя к рекламируемым товарам.

Полученные записи ключевых товаров перебираются в цикле. На этот раз страница не загромождается графическими изображениями - выводятся только названия товаров, которые при помощи ссылки связываются с полной информацией о товаре.

Листинг 14.6. Basket.asp (продолжение)

if not rsFeaturedProd.EOF then
%>

<!-- Start the display of any featured products they
didn't purchase. -->
<b>Don't forget our featured products!</b><BR><BR>

<%

end if

' Loop through the list
do until rsFeaturedProd.EOF

' Retrieve the product information to be displayed.
chrProductName = rsFeaturedProd("chrProductName")
idProduct = rsFeaturedProd("idProduct")

%>

<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<%=chrProductName%></a><BR><BR>

<%

' Move to the next record
rsFeaturedProd.MoveNext

' Loop back
Loop

%>

Получение правильного списка товаров в хранимой процедуре sp_RetrieveNonPurchFeaturedProd происходит в несколько этапов. Процедура должна вернуть записи всех ключевых товаров, отсутствующих в корзине.

При вызове хранимой процедуре передается идентификатор корзины. В секции WHERE выполняется вложенная команда SELECT, возвращающая записи всех позиций заданной корзины. В результате применения операции NOT IN в исходном наборе ключевых товаров остаются записи только тех товаров, которые отсутствуют в корзине.

Хранимая процедура дополнительно фильтрует полученный набор записей и оставляет в нем только те товары, у которых временной интервал рекламной кампании содержит текущую дату.

Листинг 14.7. Хранимая процедура sp_RetrieveNonPurchFeatureProd

CREATE PROCEDURE sp_RetrieveNonPurchFeatureProd

@idBasket int

AS

select * from products
where
intFeatured = 1 and
getdate() >= dtFeatureStart and
getdate() <= dtFeatureEnd and
products.idproduct Not In
(select idProduct from basketitem where basketitem.idbasket = @idBasket)

Остается лишь внести изменения в заголовочный файл Header.asp (см. листинг 14.8). Список ключевых товаров должен выводиться под панелью ссылок.

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

После проверки под панелью ссылок рисуется горизонтальная черта, отделяющая ссылки от перечня ключевых товаров. Под чертой выводится сообщение о наличии ключевых товаров.

Листинг 14.8. Header.asp

<!-- Check to ensure we are not on the default or basket page. -->
<%

if instr(1, lcase(Request.ServerVariables("URL")), "default.asp") = 0 and _
instr(1, lcase(Request.ServerVariables("URL")), "basket.asp") = 0 then

%>

<hr>
<font size="2" color="red">Featured Products:</font>
<br><br>

В оставшейся части добавляемого фрагмента мы открываем подключение к базе данных и выполняем хранимую процедуру sp_RetrieveFeaturedProducts, после чего перечисляем названия товаров (без графических изображений).

Листинг 14.9. Header.asp (продолжение)

<%

' Create an ADO database connection
set dbFeaturedProd = server.createobject("adodb.connection")

' Create a record set
set rsFeaturedProd = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbFeaturedProd.open("filedsn=WildWillieCDs")

' Retrieve the current featured products
sql = "execute sp_RetrieveFeaturedProducts"

' Execute the SQL statement
set rsFeaturedProd = dbFeaturedProd.Execute(sql)

' Loop through the featured products
do until rsFeaturedProd.EOF

' Retrieve the product information to be displayed.
chrProductName = rsFeaturedProd("chrProductName")
idProduct = rsFeaturedProd("idProduct")

%>

<font size="2">
<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<%=chrProductName%></a>
</font><br><br>

<%

' Move to the next record set
rsFeaturedProd.MoveNext

' Loop back
Loop

end if

%>

Посмотрим, как выглядят обновленные страницы в действии. Новая домашняя страница сайта с двумя ключевыми товарами. Обратите внимание: информация о ключевых товарах не выводится под панелью ссылок, поскольку текущей является домашняя страница.

Страница с перечнем разделов. На этот раз список ключевых товаров выводится под панелью ссылок. Он присутствует на всех страницах, кроме домашней страницы и корзины.

Включите в корзину любой товар, не входящий в список ключевых товаров. Корзина, и в нижней части страницы отображается информация о двух -ключевых товарах.

Поместите в корзину один из двух ключевых товаров. Корзина после добавления в нее товара Joe Bob's Thimble Sounds. Теперь на странице отображается реклама только одного ключевого товара Sounds of Silence (for real).

Переходим к выполнению операций с ключевыми товарами в управляющей программе.

Программирование управляющего интерфейса

Операции с ключевыми товарами будут выполняться со страницы ManageProduct.asp. Мы должны предусмотреть средства для назначения ключевых товаров, а также редактирования дат начала и конца рекламной кампании.

Новый фрагмент, добавляемый в страницу ManageProduct.asp, приведен в листинге 14.10. Для установления и снятия пометки ключевых товаров используется флажок. Мы проверяем, был ли текущий товар помечен или нет. Если товар был помечен, по умолчанию флажок переводится в установленное состояние при помощи атрибута CHECKED.

Листинг 14.10. ManageProduct.asp

<tr>
<td align="right"><b>Featured Product:</b></td>
<td>

<%

' Check to see if the product is featured.
if rsProduct("intFeatured") = 1 then

%>

<!-- Display the check box checked if the
product is featured. -->
<input type="checkbox" value="1" CHECKED name="intFeatured">

<%
else
%>

<!-- Display the check box with out the check. -->
<input type="checkbox" value="1" name="intFeatured">

<% end if %>

Страница завершается двумя текстовыми полями для редактирования начальной и конечной даты (см. листинг 14.11). Как говорилось выше, форма передает данные странице UpdateProduct.asp, где и происходит обработка этих значений.

Листинг 14.11. ManageProduct.asp (продолжение)

<!-- Show the start and end date for the product feature -->
Start Date: <input type="text" value="<%=rsProduct("dtFeatureStart")%>" size="10"
name="dtFeatureStart">
End Date: <input type="text" value="<%=rsProduct("dtFeatureEnd")%>" size="10"
name="dtFeatureEnd">

</td>
</tr>

Новый фрагмент, включаемый в страницу UpdateProduct.asp, приведен в листинге 14.12. Сначала мы читаем значение intFeatured с формы ManageProduct.asp и проверяем, был ли установлен флажок. Если флажок не был установлен, в базе данных сохраняется значение 0. После проверки читается содержимое полей начальной и конечной даты.

Листинг 14.12. UpdateProduct.asp

' Получить признак ключевого товара.
intFeatured = request("intFeatured")

' Проверить, был ли установлен флажок.
if intFeatured = "" then

' Если флажок сброшен, реклама товара не выводится
intFeatured = 0

else

' Если флажок установлен, выводить рекламу товара
intFeatured = 1

end if

dtFeatureStart = request("dtFeatureStart")
dtFeatureEnd = request("dtFeatureEnd")

После чтения данных вызывается хранимая процедура sp_UpdateProduct, обновляющая данные товара. При вызове процедуры передаются дополнительные параметры - признак ключевого товара, а также начальная и конечная даты (см. листинг 14.13).

В исходную версию хранимой процедуры sp_UpdateProduct вносятся изменения, связанные с обработкой параметров ключевых товаров (см. листинг 14.14). При вызове процедуры передается признак ключевого товара, а также две даты. Переданные значения включаются в команду SQL UPDATE.

Листинг 14.14. Хранимая процедура sp_UpdateProduct

CREATE PROCEDURE sp_UpdateProduct

@idProduct int,
@chrProductName varchar(255),
@txtDescription text,
@chrProductImage varchar(100),
@intPrice int,
@intActive int,
@intFeatured int,
@dtFeatureStart datetime,
@dtFeatureEnd datetime,
@intSalePrice int,
@dtSaleStart datetime,
@dtSaleEnd datetime

AS

update products set
chrProductName = @chrProductName, txtDescription = @txtDescription,
chrProductImage = @chrProductImage,
intPrice = @intPrice,
intActive = @intActive,
intFeatured = @intFeatured,
dtFeatureStart = @dtFeatureStart,
dtFeatureEnd = @dtFeatureEnd,
intSalePrice = @intSalePrice,
dtSaleStart = @dtSaleStart,
dtSaleEnd = @dtSaleEnd
where
idProduct = @idProduct

Рассмотрим пример практического использования управляющего интерфейса. Страница товара с новыми элементами, относящимися к ключевым товарам (флажок и два текстовых поля).

Допустим, вы решили остановить рекламную кампанию товара Joe Bob's Thimble Sounds. Снимите флажок, очистите оба текстовых поля и нажмите кнопку Update Product. Обновленная страница товара. Обратите внимание: поля даты по умолчанию инициализируются датой начала века.

Домашняя страница электронного магазина. На этот раз на ней представлен всего один ключевой товар.

СОВЕТ
Возможно, вы захотите рекламировать товары и во время оформления заказа - вроде тех мелочей, разложенных возле кассы, которые покупатель отбирает в последний момент. Для этого необходимо реализовать дополнительную логику для включения товара в корзину, обновления общей стоимости и продолжения оформления заказа.

Итоги

При помощи средств, описанных в этой главе, администратор магазина сможет легко привлечь внимание покупателей к новым товарам, ускорить продажу некоторых товаров и т. д.

В главе 15 рассматривается самый распространенный вариант проведения рекламных кампаний - распродажа. Наш подход к организации распродаж имеет много общего с рекламой ключевых товаров, но он в первую очередь ориентируется на уменьшение цены товара или общей стоимости покупки.

Глава 15. Распродажа

Распродажа!!! Не проходите мимо!

В этой главе вы узнаете, как организовать распродажу товаров по сниженным ценам и как рекламировать ее на сайте. Впрочем, подобные рекламные кампании не ограничиваются одним лишь снижением цены. Возможны и другие рекламные предложения - например, бесплатная доставка, о которой также пойдет речь в этой главе.

Информация о распродажах на уровне базы данных

В таблицу Products включаются новые поля, в которых хранится цена товара при распродаже и срок ее действия. В листинге 15.1 приведены примеры команд SQL для распродажи трех видов товаров.

Листинг 15.1. Команды SQL для распродажи товаров

update products set intSalePrice = 400, dtSaleStart = getdate (), dtStartEnd = "1/1/2001" where idProduct = 1
update products set intSalePrice = 500, dtSaleStart = getdate (), dtStartEnd = "1/1/2001" where idProduct = 2

update products set intSalePrice = 600, dtSaleStart = getdate (), dtStartEnd = "1/1/2001" where idProduct = 3

В распоряжение покупателя будут предоставлены различные средства, при помощи которых он сможет получить информацию о текущих распродажах в нашем магазине. Кроме того, в управляющей программе необходимо предусмотреть возможность установки цены для распродаваемых товаров.

Чтобы наш магазин поддерживал бесплатную доставку, в таблицу Basket необходимо включить дополнительное поле intFreeShipping. По его значению можно будет определить, распространяется ли на заказ бесплатная доставка или нет.

Кроме того, в базу данных будет включена новая таблица, содержащая информацию о том, действует ли в настоящее время рекламная кампания по бесплатной доставке. Структура таблицы приведена в табл. 15.1.

Таблица 15.1. Таблица FreeShip
Поле
Описание
idFreeShip Первичный ключ таблицы
dtStartDate Дата начала рекламной кампании по бесплатной доставке
dtEndDate Дата завершения рекламной кампании по бесплатной доставке

Таблицы базы данных обновляются кодом SQL, приведенным в листинге 15.2.

Листинг 15.2. Обновление таблиц базы данных

ALTER TABLE dbo.Basket ADD
intFreeShipping int NULL DEFAULT(0)

CREATE TABLE dbo.FreeShip (
intFreeShip int IDENTITY (1, 1) NOT NULL,
dtStartDate datetime NULL
CONSTRAINT DF_FreeShip_dtStartDate DEFAULT (getdate()),
dtEndDate datetime NULL
CONSTRAINT DF_FreeShip_dtEndtDate DEFAULT (getdate()),
CONSTRAINT PK_FreeShip PRIMARY KEY CLUSTERED
(
intFreeShip
))

Для вывода информации о бесплатной доставке на стороне покупателя нам понадобятся примеры данных. В листинге 15.3 приведена команда SQL, создающая новую запись в таблице FreeShip.

Листинг 15.3. Запись, описывающая рекламную кампанию по бесплатной доставке

insert into FreeShip(dtStartDate, dtEndDate) values (getdate() , '2/1/2000')

Переходим к построению пользовательского интерфейса.

Построение средств для организации распродажи

Изменения в программном коде электронного магазина состоят из двух шагов: вывод информации о распродаваемых товарах в процессе покупки и изменения в процессе оформления заказа для поддержки бесплатной доставки.

Вывод информации о распродаже

Информация о распродаже должна выводиться вместе с перечнем ключевых товаров на домашней странице магазина. Впрочем, необходимо действовать осторожно - распродаваемых товаров может быть много, и полный список может не поместиться на домашней странице.

Мы будем выбирать распродаваемый товар случайным образом и выводить информацию о нем перед списком ключевых товаров. В листинге 15.4 приведен фрагмент, который вставляется в файл Default.asp непосредственно перед выводом ключевых товаров.

Страница открывает подключение к базе данных и вызывает хранимую процедуру sp_RetrieveSaleProducts для получения текущего списка распродаваемых товаров.

Листинг 15.4. Default.asp

<!-- Show the featured products for today. -->
<b>On sale Today!</b><BR><BR>

<%

' Create an ADO database connection
set dbSaleProd = server.createobject("adodb.connection")

' Create a record set
set rsSaleProd = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbSaleProd.open("filedsn=WildWillieCDs")

' Retrieve all of the current sale products
sql = "execute sp_RetrieveSaleProducts"

' Execute the SQL statement
set rsSaleProd = dbSaleProd.Execute(sql)

Если хранимая процедура вернула какие-либо записи, мы произвольно выбираем одну из них для вывода на странице (см. листинг 15.5). Хранимая процедура sp_RetrieveSaleProducts возвращает столбец, содержащий общее количество возвращаемых записей. При помощи функции VBScript RND случайным образом выбирается одна из записей, информация о которой будет выводиться на странице.

После выбора индекса мы в цикле перебираем записи полученного набора. Обнаружив нужный товар, мы получаем и выводим его параметры.

Листинг 15.5. Default.asp (продолжение)

' Ensure something is returned so it can be displayed
if not rsSaleProd.EOF then

' Seed the random number generator
randomize

' Pick a random sale product to display. Note that the first
' column returned is the count of rows.
Row = Int((rsSaleProd(0) - 1 + 1) * Rnd + 1)

' Loop to the row selected.
for N = 1 to row - 1

' Move to the next row.
rsSaleProd.MoveNext

next

' Retrieve the product information to be displayed.
chrProductName = rsSaleProd("chrProductName")
chrProductImage = rsSaleProd("chrProductImage")
dblSalePrice = rsSaleProd("intSalePrice")
idProduct = rsSaleProd("idProduct")

%>

<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<img src="images/products/sm_<%=chrProductImage%>"
align="middle" border="0">
<%=chrProductName%></a>
<font color="red"><b>
- Only <%=formatcurrency(dblSalePrice/100, 2)%>
</b></font><BR><BR>

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

Затем в хранимой процедуре выполняется запрос, возвращающий данные по распродаваемым товарам. В первом столбце каждой записи возвращается общее количество записей.

Листинг 15.6. Хранимая процедура sp_RetrieveSaleProducts

CREATE PROCEDURE sp_RetrieveSaleProducts AS

declare @Cnt int

select @cnt = count(*) from products where getdate() >= dtSaleStart and getdate() <= dtSaleEnd

select @Cnt, * from products where getdate() >= dtSaleStart and getdate() <= dtSaleEnd

Сведения о распродаваемом товаре выводятся под панелью ссылок, рядом с информацией о ключевых товарах. Необходимо модифицировать заголовочный файл Header.asp и включить в него программный код для отображения распродаваемого товара.

Товар, отображаемый под панелью ссылок, как и прежде, будет выбираться случайным образом. В листинге 15.7 приведен новый фрагмент, вставляемый в Header.asp перед выводом сведений о ключевых товарах.

Как и на домашней странице, мы открываем подключение к базе данных и загружаем список распродаваемых товаров. После этого страница случайным образом выбирает один товар в списке и выводит информацию о нем под панелью ссылок. Обратите внимание - информация о распродаже, как и информация о ключевых товарах, выводится на всех страницах, кроме домашней и страницы корзины.

Листинг 15.8. Header.asp

<hr>
<font size="2" color="red">Featured Products:</font>
<br><br>

<%

' Create an ADO database connection
set dbFeaturedProd = server.createobject("adodb.connection")

' Create a record set
set rsFeaturedProd = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbFeaturedProd.open("filedsn=WildWillieCDs")

' Retrieve the current featured products
sql = "execute sp_RetrieveFeaturedProducts"

' Execute the SQL statement
set rsFeaturedProd = dbFeaturedProd.Execute(sql)

' Loop through the featured products
do until rsFeaturedProd.EOF

' Retrieve the product information to be displayed.
chrProductName = rsFeaturedProd("chrProductName")
idProduct = rsFeaturedProd("idProduct")

%>

<font size="2">
<!-- Build the link to the product information. -->
<a href="product.asp?idProduct=<%=idProduct%>">
<%=chrProductName%></a>
</font><br><br>

<%

' Move to the next record set
rsFeaturedProd.MoveNext

' Loop back
Loop

end if

%>

Итак, информация об одном из товаров, участвующих в распродаже, выводится на домашней странице и под панелью ссылок. Перейдем к странице Product.asp. На этой странице необходимо вывести сниженную цену товара и реализовать дополнительную логику, чтобы в корзине сохранялась не стандартная, а сниженная цена на товар.

В начало страницы Product.asp добавляется новый фрагмент, который проверяет, действует ли в настоящее время снижение цены на товар. Если проверка дает положительный результат, сниженная цена загружается из базы; в противном случае сниженная цена инициализируется 0. Новый фрагмент приведен в листинге 15.8.

Листинг 15.8. Product.asp

' Проверить, участвует ли товар в распродаже
if now >= cdate(rsProduct("dtSaleStart")) and _
date <= cdate(rsProduct("dtSaleEnd")) then

' Прочитать сниженную цену
intSalePrice = rsProduct("intSalePrice")

else

' По умолчанию сниженная цена инициализируется в 0.
intSalePrice = 0

end if

Далее мы займемся выводом цены. На странице товара следует вывести обе цены - как исходную, так и сниженную. В листинге 15.9 мы изменяем процесс вывода цены под графическим изображением товара и проверяем, распространяется ли на товар снижение цены. В этом случае цена распродажи выводится красным шрифтом.

Листинг 15.9. Product.asp (продолжение)

<!-- Show the product price. An input quantity box is
created. Also, several hidden variables will hold
key data for adding the product to the database. -->
<TR>
<TD align="center"><B>Price:
<%=formatcurrency(intPrice/100, 2)%></b>

<!-- Check to see if the product is on sale. -->
<% if intSalePrice <> 0 then %>

<!-- Show the sale price -->
<font color="red"><b>
<BR><BR> On Sale Now for
<%=formatcurrency(intSalePrice/100, 2)%>!
</font></b>

<% end if %>

</td>

В листинге 15.10 строится текстовое поле для количества единиц товара и скрытые поля. Затем мы проверяем, участвует ли товар в распродаже, и, если участвует, в скрытое поле вместо цены товара заносим сниженную цену распродажи. В результате товар заносится в корзину по сниженной цене.

Листинг 15.10. Product.asp (продолжение)

<TD align="center">
<B>Quantity:
<input type="text" value="1" name="quantity" size="2"></b>
<input type="hidden" value="<%=idProduct%>" name="idProduct">
<input type="hidden" value="<%=chrProductName%>" name="ProductName">
<%
' Check to see if the product is on sale.
if intSalePrice = 0 then
%>
<!-- Set the hidden price to the standard price. -->
<input type="hidden" value="<%=intPrice%>" name="ProductPrice">
<%
else
%>
<!-- Set the hidden price to the sale price. -->
<input type="hidden" value="<%=intSalePrice%>" name="ProductPrice">
<%
end if
%>

</td>
</TR>

СОВЕТ
Если запас распродаваемых товаров на складе недостаточен, можно установить ограничения на количество заказываемых товаров. Например, можно разрешить покупателю приобрести за определенный период времени не более четырех единиц товара по всем распродажам. Эту информацию можно хранить в профиле покупателя.

На этом построение интерфейса управления для организации распродаж завершается. Посмотрим, как он работает на практике. На рис. 15.1 изображена домашняя страница, в которой информация о распродаваемом товаре выводится перед списком ключевых товаров.

Панель ссылок, отображаемая на странице разделов. Информация о товаре, продаваемом по сниженной цене, также выводится перед списком ключевых товаров.

Страница товара, участвующего в распродаже. Обратите внимание - сниженная цена выводится красным шрифтом под стандартной ценой товара. Попробуем включить товар в корзину.

Корзина, в которую был включен распродаваемый товар. Обратите внимание - в поле цены указана цена распродажи. Даже если вы измените количество заказанных единиц товара, цена за единицу останется постоянной вплоть до оформления заказа.

Реализация бесплатной доставки

Перейдем к реализации бесплатной доставки. Общий принцип таков: в определенные дни, зависящие от содержимого таблицы FreeShip, доставка заказанных товаров осуществляется бесплатно.

Начнем со страницы Payment.asp (см. листинг 15.11). Изменения вносятся в ту часть страницы, где вызываются функции Tax и Shipping компонента ECStoreBizLogic. В листинге 15.11 приведен новый фрагмент, начинающийся с проверки того, что количество заказанных единиц больше 0.

Прежде всего мы открываем подключение к базе данных, чтобы получить данные из таблицы FreeShip. Чтобы узнать, действует ли в настоящий момент рекламная кампания по бесплатной доставке, мы вызываем хранимую процедуру sp_CheckFreeShip.

Если результат проверки окажется положительным, функцию Shipping компонента ECStoreBizLogic вызывать не нужно. В противном случае функция вызывается, как обычно. Присваивая сеансовой переменной FreeShipping значение 1, мы тем самым показываем, что в настоящий момент действует кампания по бесплатной доставке.

Листинг 15.11. Payment.asp

' Check the quantity returned from the database
if rsBasket("quantity") > 0 then

' Create an ADO database connection
set dbFreeShip = server.createobject("adodb.connection")

' Create the record set
set rsFreeShip = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbFreeShip.open("filedsn=WildWillieCDs")

' Check to see if free shipping is in effect.
sql = "execute sp_CheckFreeShip"

' Execute the statement
set rsFreeShip = dbBasket.Execute(sql)

' Check to see if a row was returned which indicates free
' shipping is currently in effect.
if rsFreeShip.EOF then

' Call the shipping function of our component. The quantity
' is passed in and must be in a long data type format. The
' Shipping fee is returned.
Shipping = BizLogic.Shipping(clng(rsBasket("quantity")))

' Indicate free shipping is not in effect
session("FreeShipping") = 0

else

' Default the shipping to 0.
Shipping = 0

' Indicate free shipping is in effect.
session("FreeShipping") = 1

end if

else

' Redirect to the basket page since the quantity is 0
Response.Redirect("Basket.asp")

end if

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

Листинг 15.12. Payment.asp (продолжение)

' Store the shipping value in a session variable
session("Shipping") = Shipping

' Store the quantity in a session variable
session("Quantity") = rsBasket("quantity")

' Calculate the tax by calling the Tax function of
' our component. We pass in the shipping state and the
' order subtotal. The value is also stored in a session
' variable.
Tax = BizLogic.tax(session("chrShipState"), clng(subtotal))
session("Tax") = Tax

' Calculate the total and store in a session variable.
Total = SubTotal + Shipping + Tax
session("Total") = Total

%>

<HTML>

<!-- #include file="include/header.asp" -->

<BR>

<center>
<font size="5"><b>Billing Information</b></font>
</center>

<BR>
<b>Order Recap:</b>
<BR><BR>

<!-- Build a table to display the order total -->
<table>

<!-- Display the Subtotal -->
<tr>
<td align="right">Subtotal:</td>
<td><%=formatcurrency(Subtotal/100, 2)%></td>
</tr>

<!-- Display the Shipping Value -->
<tr>
<td align="right">

<!-- Check to see if Free Shipping is in effect. -->
<% if session("FreeShipping") = 0 then %>
<!-- Indicate standard shipping -->
Shipping:
<% else %>
<!-- Indicate free shipping -->
<font color="red"><b>
Free Shipping Today!
</b></font>
<% end if %>

</td>
<td><%=formatcurrency(Shipping/100, 2)%></td>
</tr>

Хранимая процедура sp_CheckFreeShip (см. листинг 15.13) проверяет, действует ли в настоящее время рекламная кампания по бесплатной доставке. Для этого даты начала и завершения кампании сравниваются с текущей системной датой, полученной при помощи функции GetDateC).

Листинг 15.13. Хранимая процедура sp_CheckFreeShip

CREATE PROCEDURE sp_CheckFreeShip

AS

select * from FreeShip where getdate() >= dtStartDate and getdate() <= dtEndDate

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

В листинге 15.14 приведен новый фрагмент кода страницы ValidatePayment.asp. Обновляется код, сохраняющий вычисленные значения в корзине. Хранимая процедура sp_UpdateBasket модифицируется таким образом, чтобы ей передавался дополнительный параметр FreeShipping. Обратите внимание: при бесплатной доставке сеансовой переменной Shipping присваивается 0.

Листинг 15.14. ValidatePayment.asp

'***********************************************
'**** 6. Update the basket with the final
'**** order data.
'***********************************************

' Finally we need to update the basket with the final
' amounts for quantity, subtotal, shipping, tax and
' total
sql = "execute sp_UpdateBasket " & _
session("idBasket") & ", " & _
session("Quantity") & ", " & _
session("Subtotal") & ", " & _
session("Shipping") & ", " & _
session("FreeShipping") & ", " & _
session("Tax") & ", " & _
session("Total") & ", 1"

Как упоминалось выше, хранимую процедуру sp_UpdateBasket также необходимо модифицировать для того, чтобы ей передавался признак бесплатной доставки (см. листинг 15.15). Новый параметр присваивается полю intFreeShipping и сохраняется в базе командой UPDATE.

Листинг 15.15. Хранимая процедура sp_UpdateBasket

/* Обновление содержимого корзины */
CREATE PROCEDURE sp_UpdateBasket

/* При вызове процедуре передается идентификатор корзины, количество единиц товара, общая стоимость заказа, стоимость доставки, признак бесплатной доставки, налог, итоговая стоимость и признак размещения заказа. */
@idBasket int,
@intQuantity int,
@intSubTotal int,
@intShipping int,
@intFreeShipping int,
@intTax int,
@intTotal int,
@intOrderPlaced int

AS

/* Обновление корзины */
update basket set
intQuantity = @intQuantity,
intSubtotal = @intSubtotal,
intShipping = @intShipping,
intFreeShipping = @intFreeShipping, intTax = @intTax,
intTotal = @intTotal,
intOrderPlaced = @intOrderPlaced
where idBasket = @idBasket

СОВЕТ
Существуют и другие способы снижения стоимости доставки. Например, можно организовать бесплатную доставку заказов, у которых общая стоимость превышает некоторое пороговое значение, или обеспечить бесплатную доставку каждого третьего заказа. Все эти рекламные средства играют важную роль в привлечении покупателей.

Проверим, как работают средства бесплатной доставки. Не забудьте создать в таблице FreeShip запись, у которой текущая дата входит в интервал дат рекламной кампании.

На рис. 15.5 изображена страница ввода платежных реквизитов. Как видно из рисунка, пользователю не придется оплачивать доставку.

Перейдите к оформлению заказа. Проверьте состояние заказа и убедитесь в том, что информация о бесплатной доставке сохранилась в базе данных.

Построение интерфейса для управления распродажами

Познакомившись с работой пользовательского интерфейса, мы переходим к рассмотрению административных средств, предназначенных для организации распродаж и управления бесплатной доставкой товара.

Сразу же после кода управления ключевыми товарами, включенного в страницу ManageProduct.asp, будет добавлен аналогичный код для организации распродаж. Нам понадобятся текстовые поля для редактирования цены, начальной и конечной даты. В таблице создается новая строка с текстовыми элементами для редактирования полей базы данных intSalePrice, dtSaleStart и dtSaleEnd.

Листинг 15.16. ManageProduct.asp

<!-- Параметры рекламных кампаний по распродаже. -->
<tr>
<td align="right"><b>Sale Price:</b></td>
<td>

<!-- Текстовое поле для цены распродажи. -->
<input type="text" value="<%=intSalePrice/100%>"
name="intSalePrice" size="10">

<!-- Текстовые поля для дат начала и конца рекламной кампании. -->
Start Date: <input type="text" value="<%=dtSaleStart%>"
size="10" name="dtSaleStart">
End Date: <input type="text" value="<%=dtSaleEnd%>"
size="10" name="dtSaleEnd">

</td>
</tr>

В страницу UpdateProduct.asp вносятся изменения, связанные с получением новых данных и обновлением базы. Изменения в коде страницы приведены в листинге 15.17. Необходимые значения читаются из переменных формы.

Хранимая процедура sp_UpdateProduct также должна получать параметры, связанные с распродажей. Ей передаются значения, полученные из формы.

Листинг 15.17. UpdateProduct.asp

' Retrieve the sale price and start and end
' date for the sale price campaign.
intSalePrice = request("intSalePrice") * 100
dtSaleStart = request("dtSaleStart")
dtSaleEnd = request("dtSaleEnd")

' Create an ADO database connection
set dbProduct = server.createobject("adodb.connection")

' Create the record set
set rsProduct = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbProduct.open("filedsn=WildWillieCDs")

' Execute the SQL stored procedure to update the
' product data
sql = "execute sp_UpdateProduct " & _
request("idProduct") & ", '" & _
chrProductName & "', '" & _
txtDescription & "', '" & _
chrProductImage & "', " & _
intPrice & ", " & _
intActive & ", " & _
intFeatured & ", '" & _
dtFeatureStart & "', '" & _
dtFeatureEnd & "', " & _
intSalePrice & ", '" & _
dtSaleStart & "', '" & _
dtSaleEnd & "'"

' Execute the statement
set rsProduct = dbProduct.Execute(sql)

' Send the user back to the product manager page and
' pass back the product i.
Response.Redirect "ManageProduct.asp?idProduct=" & _
request("idProduct")

В листинге 15.18 приведен новый вариант хранимой процедуры sp_UpdateProduct. Для каждого из полей, связанных с распродажей, процедуре передается новый параметр. Команда UPDATE присваивает переданные значения новым полям базы данных.

Листинг 15.18. Хранимая процедура sp_UpdateProduct

CREATE PROCEDURE sp_UpdateProduct

@idProduct int,
@chrProductName varchar(255),
@txtDescription text,
@chrProductImage varchar(100),
@intPrice int,
@intActive int,
@intFeatured int,
@dtFeatureStart datetime,
@dtFeatureEnd datetime,
@intSalePrice int,
@dtSaleStart datetime,
@dtSaleEnd datetime

AS

update products set
chrProductName = @chrProductName, txtDescription = @txtDescription,
chrProductImage = @chrProductImage,
intPrice = @intPrice,
intActive = @intActive,
intFeatured = @intFeatured,
dtFeatureStart = @dtFeatureStart,
dtFeatureEnd = @dtFeatureEnd,
intSalePrice = @intSalePrice,
dtSaleStart = @dtSaleStart,
dtSaleEnd = @dtSaleEnd
where
idProduct = @idProduct

Как видите, программный код для управления распродажами получился довольно простым. Страница Product.asp c новыми полями. Вы можете отредактировать содержимое этих полей и обновить сведения о товаре.

Внесите необходимые изменения и нажмите кнопку Update Product.

Тема управления распродажами на этом завершается, и мы переходим к управлению рекламными кампаниями по бесплатной доставке.

Управление рекламными кампаниями по бесплатной доставке

В настоящее время в нашем магазине не предусмотрены никакие средства управления бесплатной доставкой. Следовательно, мы должны создать дополнительную ссылку на страницах ManagerMenu.asp и Navlnclude.asp. В листингах 15.19 и 15.20 приведены новые фрагменты, которые включаются в эти страницы для создания новой ссылки.

На странице ManagerMenu.asp в таблице создается дополнительная строка, содержащая ссылку на страницу ManageFreeShipping.asp.

Листинг 15.19. ManagerMenu.asp

<tr>
<!-- Управление бесплатной доставкой -->
<td><a href="ManageFreeShipping.asp">
Manage Free Shipping</a></td>
</tr>

В листинге 15.20 на панели ссылок создается новая ссылка Manage Free Shipping, также связанная со страницей ManageFreeShipping.asp.

Листинг 15.20. NavInclude.asp

<!-- Ссылка на страницу управления бесплатной доставкой. -->
<a href="ManageFreeShipping.asp">
Manage Free Shipping</a>

В интерфейс администратора добавляется новая страница, ManageFreeShipping.asp (см. листинг 15.21), предназначенная для управления рекламными кампаниями по бесплатной доставке. Страница начинается с включения стандартных заголовочных файлов, обеспечивающих проверку пользователя и построение панели ссылок.

Листинг 15.21. ManagerFreeShipping.asp

<%@ Language=VBScript %>
<!-- #Include file="include/validatecheck.asp" -->
<HTML>
<!--
ManageFreeShipping.asp - Provides options to set the
next free shipping campaign date range.
-->

<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
</HEAD>
<BODY>

<!-- #include file="include/navinclude.asp" -->

<BR><BR>
<B>Set free shipping campaign:
</b><BR><BR>

Продолжение приведено в листинге 15.22. Прежде всего мы открываем подключение к базе данных, чтобы прочитать текущие сроки бесплатной доставки. Загрузка данных из базы выполняется хранимой процедурой sp_RetrieveFreeShipping.

Листинг 15.22. ManagerFreeShipping.asp (продолжение)

<%
' Создать объект подключения к базе данных
set dbFreeShipping = server.createobject("adodb.connection")

' Создать объект набора записей
set rsFreeShipping = server.CreateObject("adodb.recordset")

' Открыть подключение, используя файловый DSN ODBC
dbFreeShipping.open("filedsn=WildWillieCDs")

' Хранимая процедура sp_RetrieveFreeShip возвращает текущие
' сроки рекламной кампании по бесплатной доставке.
sql = "execute sp_RetrieveFreeShip"

' Выполнить команду
set rsFreeShipping = dbFreeShipping.Execute(sql)
%>

Затем создается форма для передачи начальной и конечной даты кампании по бесплатной доставке. Форма завершается кнопкой отправки данных, после чего следуют закрывающие теги страницы (см. листинг 15.23).

Листинг 15.23. ManagerFreeShipping.asp (продолжение)

<!-- The changes will be posted to the UpdateFreeShipping.asp
page. -->
<form method="post" action="UpdateFreeShipping.asp">

<!-- Start a table to show the start and end date. -->
<table cellpadding="3" cellspacing"3">
<!-- Show the start date. -->
<tr>
<td align="right">Start Date:</td>
<td>
<input type="text" name="dtStartDate"
value="<%=rsFreeShipping("dtStartDate")%>">
</td>
</tr>
<!-- Show the end date. -->
<tr>
<td align="right">End Date:</td>
<td>
<input type="text" name="dtEndDate"
value="<%=rsFreeShipping("dtEndDate")%>">
</td>
</tr>

<!-- Show a submit button for the form -->
<tr><td align="center" colspan="2">
<input type="submit" value="Submit" name="Submit">
</td></tr>
</table>

</form>

</BODY>
</HTML>

ВНИМАНИЕ
Функции обработки дат предполагают, что в системе используется локальный контекст США, в котором даты кодируются в формате мм/дд/гг. При заполнении формы данные следует вводить именно в этом формате, в противном случае могут возникнуть непредвиденные ошибки.

Хранимая процедура sp_RetrieveFreeShip (cм. листинг 15.24) возвращает все записи в таблице. В действительности обрабатывается только первая запись, поскольку в любой момент времени может действовать лишь одна кампания по бесплатной доставке. Впрочем, при желании можно реализовать средства для создания нескольких кампаний и их планирования.

Листинг 15.24. Хранимая процедура sp_RetrieveFreeShip

CREATE PROCEDURE sp_RetrieveFreeShip AS

select * from FreeShip

Страница UpdateFreeShipping.asp (см. листинг 15.25) обновляет данные в таблице FreeShip. Сначала она открывает подключение к базе данных, после чего вызывает хранимую процедуру sp_UpdateFreeSh1p, которая вносит изменения в базу данных.

Листинг 15.25. UpdateFreeShipping.asp

<%@ Language=VBScript %>
<%

' ****************************************************
' UpdateFreeShipping.asp - Handles updating the free
' shipping campaign dates.
' ****************************************************

' Retrieve the start date
dtStartDate = request("dtStartDate")

' Retrieve the end date
dtEndDate = request("dtEndDate")

' Create an ADO database connection
set dbFreeShip = server.createobject("adodb.connection")

' Create the record set
set rsFreeShip = server.CreateObject("adodb.recordset")

' Open the connection using our ODBC file DSN
dbFreeShip.open("filedsn=WildWillieCDs")

' Execute the sp_UpdateFreeShip stored procedure
' to change the dates.
sql = "execute sp_UpdateFreeShip '" & _
dtStartDate & "', '" & _
dtEndDate & "'"

' Execute the statement
set rsFreeShip = dbFreeShip.Execute(sql)

' Send the user back to free shipping manager page.
Response.Redirect "ManageFreeShipping.asp"

%>

Хранимая процедура sp_UpdateFreeShip приведена в листинге 15.26. При вызове ей передаются начальная и конечная дата рекламной кампании. На этот раз обновляются все записи, существующие в таблице.

Листинг 15.26. Хранимая процедура sp_UpdateFreeShip

CREATE PROCEDURE sp_UpdateFreeShip

@dtStartDate datetime,
@dtEndDate datetime

AS

Update FreeShip set dtStartDate = @dtStartDate, dtEndDate = @dtEndDate

Также необходимо внести изменения в систему вывода отчетов о заказах. В базе данных должна храниться информация о том, что при размещении заказа действовала бесплатная доставка, и в случае обновления заказа по какой-либо причине эта информация не должна теряться.

Новый код страницы OrderDetail.asp приведен в листинге 15.27. Чтобы узнать, действует ли в настоящий момент кампания по бесплатной доставке, мы проверяем значение поля intFreeShippingB базе данных. Если оно равно 1, выводится сообщение о бесплатной доставке; в противном случае выводится стандартный текст. Кроме того, информацию о бесплатной доставке необходимо передать странице UpdateOrder.asp. Независимо от результата проверки значение сохраняется в скрытом поле на форме и передается странице UpdateOrder.asp для обработки.

Листинг 15.27. OrderDetail.asp

<!-- Show the shipping total of the basket -->
<tr>
<td colspan="5" align="right">
<!-- Check to see if we have free shipping. -->
<% if rsOrderReceiptHeader("intFreeShipping") = 1 then %>
<!-- Show that there is free shipping on this order. -->
<b><font color="red">
Free Shipping:</b></font>
<input type="hidden" value="1" name="intFreeShipping">
<% else %>
<!-- Show that there is standard shipping on this order. -->
<b>Shipping:</b>
<input type="hidden" value="0" name="intFreeShipping">
<% end if %>
</td>
<td align="right"><%Response.Write _
formatcurrency(rsOrderReceiptHeader("intShipping")/100, 2) %></td>
</tr>

Страница UpdateOrder.asp обновляет данные заказа в соответствии с изменениями, внесенными на странице OrderDetail.asp. Например, пользователь мог изменить количество единиц заказанного товара, что, в свою очередь, повлияет на общую стоимость заказа и значения вычисляемых полей.

Изменения начинаются с того места, где с формы читаются значения данных заголовка. В этом фрагменте дополнительно читается значение intFreeShipping (см. листинг 15.28).

Листинг 15.28. UpdateOrder.asp

' Next we retrieve the core order data which
' includes the billing address and shipping
' address. Note that the key fields are updated
' to ensure any single quotes are doubled.
chrBillFirstName = replace(request("chrBillFirstName"), "'", "''")
chrBillLastname = replace(request("chrBillLastName"), "'", "''")
chrShipFirstName = replace(Request("chrShipFirstName"), "'", "''")
chrShipLastname = replace(request("chrShipLastName"), "'", "''")
chrBillAddress = replace(request("chrBillAddress"), "'", "''")
chrShipAddress = replace(request("chrShipAddress"), "'", "''")
chrBillCity = replace(request("chrBillCity"), "'", "''")
chrBillState = request("chrBillState")
chrBillZipCode = request("chrBillZipCode")
chrShipCity = replace(request("chrShipCity"), "'", "''")
chrShipState = request("chrShipState")
chrShipZipCode = request("chrShipZipCode")
chrBillPhone = request("chrBillPhone")
chrShipPhone = request("chrShipPhone")
chrBillEmail = request("chrBillEmail")
chrShipEmail = request("chrShipEmail")

' Get the free shipping setting for the order.
intFreeShipping = request("intFreeShipping")

В листинге 15.29 модификация UpdateOrder.asp продолжается. Как и на странице Payment.asp, мы проверяем, действует ли в настоящее время кампания по бесплатной доставке. Если доставка осуществляется бесплатно, функция Shipping компонента ECStoreBizLogic не вызывается.

После определения стоимости доставки информация корзины обновляется вычисленными значениями. При бесплатной доставке переменная Shipping равна 0. Хранимая процедура sp_UpdateBasket сохраняет в базе все параметры корзины, включая поле intFreeShipping.

ПРИМЕЧАНИЕ
Наш тривиальный сценарий открывает немалый простор для творчества. Например, вы можете предоставить администратору возможность отменять бесплатную доставку для конкретных заказов, или хранить в базе данных информацию о нескольких рекламных кампаниях. Программа была написана так, чтобы подобные модификации можно было вносить как можно проще, и при желании вы можете реализовать эти возможности самостоятельно.

Листинг 15.29. UpdateOrder.asp (продолжение)

' Check to see if there is free shipping on the order.
if intFreeShipping = 0 then

' Create the Bussiness Logic component to
' calculate the tax and shipping.
set BizLogic = server.CreateObject("ECStoreBizLogic.TaxShip")

' Call the shipping function of our component. The quantity
' is passed in and must be in a long data type format. The
' Shipping fee is returned.
Shipping = BizLogic.Shipping(cLng(TotalQuantity))

else

' Otherwise we default the shipping total to 0.
Shipping = 0

end if

' Calculate the tax by calling the Tax function of
' our component. We pass in the shipping state and the
' order subtotal. The value is also stored in a session
' variable.
Tax = BizLogic.tax(cstr(chrShipState), clng(subtotal))

' Calculate the new total.
Total = subtotal + shipping + tax

' Build a SQL statement to update the basket data
sql = "execute sp_UpdateBasket " & _
idBasket & ", " & _
TotalQuantity & ", " & _
SubTotal & ", " & _
Shipping & ", " & _
intFreeShipping & ", " & _
Tax & ", " & _
Total & ", 1"

' Execute the SQL statement
set rsOrderUpdate = dbOrderUpdate.execute(sql)

' Send the user back to the order detail
' page
Response.Redirect "OrderDetail.asp?idOrder=" & idOrder & _
"&idShopper=" & idShopper

%>

Давайте рассмотрим работу страниц управляющего интерфейса на конкретном примере. На рис. 15.9 показано меню управляющей программы с новым пунктом Manage Free Shipping, предназначенным для управления бесплатной доставкой. Щелкните на этой ссылке.

Страница управления бесплатной доставкой. На ней находятся всего два поля, в которых вводится срок проведения следующей рекламной кампании.

Итоги

На этом завершается наше знакомство с управлением распродажами и кампаниями по бесплатной доставке заказов. Мы всего лишь в общих чертах познакомились с возможностями, используемыми при проведении рекламных кампаний и продаже товаров по сниженным ценам. Существует множество других идей и стратегий - например, объединение всех распродаваемых товаров в специальном разделе магазина, многоступенчатые скидки в зависимости от объемов заказа и т. д.