9. Корзина и оформление заявки
10 декабря 2016 г. 6:58
В Django SHOP содержимое корзины всегда хранится в базе данных. В предыдущих версиях фреймворка, содержимое корзины хранилось в сессии для безымянных пользователей, а для зарегистрированных пользователей - в базе данных. Сейчас корзина всегда хранится в базе данных. Такой подход упрощает код и немного экономит оперативную память, но добавляет другую незначительную проблему.
С технической точки зрения, страница оформления заказа - такая же как корзина. Они могут быть на разных страницах или располагаться на одной. То что мы, обычно, называем "Страницей оформления заказа" - это всего лишь набор Cascade плагинов, поэтому в этом разделе мы не будем вдаваться в подробности.
9.1. Просроченные корзины
Сессии истекают, а содержимое корзины анонимных покупателей все ещё остаются в базе данных. Поэтому мы должны позаботиться о том, чтобы эти корзины тоже истекали, так как ими никто не будет пользоваться, возможно, кроме некоторых экспертов интеллектуального анализа данных.
Вызывая
./manage.py shopcustomers Customers in this shop: total=3408, anonymous=140, expired=88, active=1108, guests=2159, registered=1109, staff=5.
мы собираем некоторую статистику о покупателях, посетивших наш сайт. В этом примере мы видим, что 1109 покупателей осуществляют покупки как зарегистрированные пользователи, а 2159 - как гости. Имеются 88 покупателей в базе данных, но их сессию можно считать истекшей, так как они больше не имеют ассоциированной сессии.
Вызов комманды
./manage.py shopcustomers --delete-expired
удалит этих пользователей с истекшим сроком годности и их соответствующие просроченные корзины. Эта задача может быть поставлена в cron для ежедневного или еженедельного выполнения.
9.2. Модели корзины
Корзина состоит из двух классов модели: Cart и CartItem, которые наследуются от BaseCart и BaseCartItem соответственно. Также как и с большинством моделей в django SHOP, эти модели тоже используют Deferred Model Pattern (Паттерн отложенной модели), поэтому наследование от базового класса автоматически устанавливает внешний ключ на соответствующую модель. Это даёт программисту гибкость в добавлении стольких полей в корзину, сколько требуется продавцу для необходимой реализации.
В большинстве случаев дефолтной реализации корзины вполне хватает для работоспособности интернет-магазина. Эти дефолтные классы могут быть найдены в shop.models.defaults.cart.Cart и shop.models.defaults.cart_item.CartItem. Чтобы материализовать дефолтную реализацию, достаточно импортировать эти два файла в приложение торговли. В противном случае нам нужно создать собственную реализацию корзины, которая наследуется от BaseCart и BaseCartItem. Так как количество элементов не всегда может быть представлено натуральным количеством, это поле должно быть добавлено в реализацию CartItem вместо своего базового класса. Его тип поля должен позволять арифметические операции, поэтому только IntegerField, FloatField или DecimalField могут использоваться в качестве количества элементов.
Убедитесь, что модель CartItem импортировано (и материализовано) перед моделью Product и классы произведены от него.
Модель Cart использует свой собственный менеджер. Так как имеется только одна корзина для покупателя, доступ к корзине должен быть выполнен с помощью request объекта. Мы всегда можем получить доступ к корзине для текущего покупателя вызвав:
from shop.models.cart import CartManager cart = CartModel.objects.get_or_create_from_request(request)
Добавление продукта в корзину, должно выполняться следующим образом:
from shop.models.cart import CartItemManager cart_item = CartItemManager.get_or_create( cart=cart, product=product, quantity=quantity, **extras)
Возвращает новый объект элемент корзины, если данный продукт не может быть найдет в текущей корзине. Иначе возвращается существующий элемент корзины, количество которого увеличено на данное значение. Для продуктов с вариациями не всегда легко определить есть ли товар в корзине или нет. Так как django SHOP не может сообщить о том, как отличаются виды продуктов, то решение данного вопроса предоставляется для вас. Поэтому реализация классов продуктов должны переопределять метод is_in_cart(). Этот метод используется, чтобы сообщить CartItemManager существует ли продукт в корзине или это новый продукт.
Всякий раз, когда метод cart.update(request) вызывается, модификаторы корзины пересчитывают все элементы в корзине. Тем самым обновляются итоговые строки, подытог, дополнительные расходы и окончательная сумма.
9.2.1. Список просмотренных товаров (Watch List)
Вместо реализации раздельного watch-list (некоторые могут сказать wish-list), django SHOP использует простой трюк. Всякий раз, когда количество товара в корзине равно нулю, этот элемент считается в списоке просмотренных товаров. Иначе, считается в корзине. Идея состоит в следующем: если количество равно нулю, то смысла нет обозначать товар, что он в корзине. Но с другой стороны, такие товары можно обозначить, что они в списке просмотренных товаров. Поэтому уменьшение количества товара до нуля - это тоже самое, что оставить его в просмотренных товаров, не желая купить его.
9.3. Cart Views
Отобразить корзину в django Shop также просто, как добавить любую другую страницу в CMS. Перейдите в административую часть сайта и откройте структуру страниц CMS. В подходящем месте в структуре добавьте новую страницу. В качестве названия страницы вы можете использовать “Cart”, “Basket”, “Warenkorb”, “Cesta” или другое подходящее название для этого сайта. Мультиязычные настройки в CMS позволяют задать название страницы для каждого языка.
В редакторе страницы щёлкните на кнопку Расширенные настройки (Advanced Settings), которая располагается внизу страницы. В качестве шаблона, выберите шаблон по умолчанию, который предоставляет по крайней мере один большой заполнитель.
Введите “shop-cart” в поле Id. Этот идентификатор требуется некоторыми шаблонами, в которых используется ссылка на страницу корзины. Если поле не заполнено, то некоторые ссылки в шаблонах могут не работать.
Предлагается отметить данную страницу как Soft root. Это предотвращает появление элемента меню “Корзина” рядом с другими страницами CMS. Вместо этого, мы предпочитаем отобразить специальный значок корзины, расположенный справа от панели навигации (меню).
9.3.1. Корзина с использованием Cascade плагинов
Перейдите в режим "Структура" для использования djangocms-cascade. В главном заполнителе добавьте Row, а затем в него Column, которые могут быть найдены в разделе Bootstrap. Внутрь плагина Column, добавьте дочерний плагин Корзина из раздела Магазин. Этот плагин может отображатья четырьмя разными способами:
9.3.1.1. Редактируемая корзина
“Редактируемая корзина” рендерится с помощью шаблонного движка Angular JS. Это означает что покупатель может изменять количество товаров в корзине, удалять их или перемещать в список желаний. Каждое обновление сразу же отражается на подитог, дополнительные поля и финальный итог суммы.
При использовании выше показанной структуры плагинов ваша корзина будет выглядеть примерно так:
В зависимости от выбранного шаблона это отображение может различаться.
9.3.1.2. Статическая корзина
Альтернатива редактируемой корзине - "Статическая корзина". Здась элементы корзины рендерятся с помощью шаблонного движка Django. Так как здесь всё статически, поэтому количество товара не может быть изменено. И тем самым покупателю ничего не остаётся сделать, как просто продолжить оформление заказа без возможности изменения количества. Возможно, использование такой корзины имеет смысл при покупке единичного продукта.
9.3.1.3. Итоги корзины
Отображает только подитог корзины, дополнительные поля корзины, такие как налог, стоимость перевозки и итоговую стоимость.
9.3.1.4. Просмотренные товары
Специальное представление корзины - это просмотренные товары. Он может быть использоваться покупателями, которые хотят запомнить товары, например, для сравнения или их покупки позже. По умолчанию этот список просмотренных товаров редактируемый, но не возволяющий изменять количество. Это сделано так, потому что список просмотренных товаров имеет туже модель, что и товар в корзине. Если количество товара равно нулю, то этот товар считается в списке просмотренных товаров. И поэтому-то, кстати, очень легко переместить товары из корзины в список просмотренных товаров и наоборот. Эта концепция также не позволяет иметь товар одновременно и в корзине, и в списке просмотренных товаров. Очень часто в онлайн шоппингах происходит такая путаница.
9.3.1.5. Рендер шаблонов
Путь шаблонов, используемых для рендера корзины, строится по следующим правилам:
- Отыскать папку, названную согласно названию проекта, т. е. settings.SHOP_APP_LABEL в нижнем регистре. Если такая папка не найдена, то используется папка shop.
- Найти подпапку cart.
- Найти шаблон, названный editable.html, static.html, watch.html или summary.html.
Эти шаблоны написаны так, чтобы их можно было легко кастомизировать. Для того чтобы переопределить “editable cart” добавьте шаблон по пути, скажем, myshop/cart/editable.html в папку folder. И замените значение расширяемого шаблона на {% extend "shop/cart/editable.html" %} для того, чтобы просто переопределять нужные блоки {% block %}...{% endblock %}.
Многие из этих шаблонных блоков включают в себя HTML фрагменты такие, как <script id="shop/....html" type="text/ng-template">. Причина этого заключается в том, что редактируемая корзина рендерится в браузере с помощью AngularJS, используя так называемые директивы. Следовательно, она становится очень прямолинейной для переопредения Angular шаблонов скриптов, используя внутренний механизм шаблонов Django.
9.3.1.5.1. Несколько шаблонов
Если по некоторым причинам нам нужны различные шаблоны корзины, то мы должны добавить этот код в settings.py:
CMSPLUGIN_CASCADE_PLUGINS_WITH_EXTRA_RENDER_TEMPLATES = { 'ShopCartPlugin': ( (None, _("default")), # the default behavior ('myproject/cart/other-editable.html', _("extra editable")), ) }
Таким образом, добавится дополнительная кнопка выбора в окне редактора корзины. Администратор сайта может выбрать либо шаблон по умолчанию, либо дополнительный шаблон корзины.
9.3.1.5.2. Продолжить для оформления заказа
На странице отображения корзины продавец может решить, будет ли он размещать формы оформления заказа вместе с корзиной, или он выведет их на отдельной странице. С технической точки зрения, это не имеет никакого значения, если корзина и оформления заказа объединены на одной странице CMS, или если они разделены на две или несколько страниц. В последнем случае просто добавьте кнопку в конце каждой страницы: это позволит покупателю легко перейти к следующей странице.
На странице оформления заказа, клиент должен заполнить несколько форм: контактная форма, формы доставки и адреса оплаты, формы онлайн-оплаты и способы доставки, и многое другое. Каждые из них зависят от конфигурации, правовыми нормами и требованиями реализации магазина. В Cascade плагины перечислены все CMS плагины, которые относятся к магазину. Они могут быть объединены для реализации хорошей страницы оформления заказа.
На странице оформления заказа, клиент должен заполнить несколько форм. Они могут быть контактную форму, доставки и адреса биллинга, оплаты и способы доставки, и многое другое. Какие из них зависят от конфигурации, правовыми нормами и требованиями реализации магазина. В Cascade плагинов все покупки конкретных CMS плагины перечислены. Они могут быть объединены в то, что имеет смысл для успешной проверки.
9.3.2. Добавление корзины через вручную написанный шаблон корзины
Вместо использования системы CMS плагинов, шаблон для корзины может быть также реализован вручную. На основе существующего шаблона страницы, найдите элемент, где корзина должна быть вставлена. Затем используйте один из существующих шаблонов в папке django-shop/shop/templates/shop/cart/ в качестве отправной точки и вставьте его в подходящее место в шаблоне страницы. Далее, в settings.py, добавьте этот специализированный шаблон к списку CMS_TEMPLATES и выберите его для этой страницы.
С технической точки зрения, не имеет никакого значения, будем ли мы использовать плагин Корзина или вручную написанный шаблон. HTML-код, создающий корзину, должен подходить требованиям продавца, и, обычно, это является более гибким подходом, если мы переопределить код шаблона, как описано в разделе Рендер шаблонов. Поэтому, настоятельно рекомендуется, чтобы шаблоны Корзина и Оформление заказа были выполнены вручную.
9.4. Модификаторы корзины
Модификаторы корзины - это простые плагины, которые позволяют продавцу определить (программным способом) правила: как стоимость товаров рассчитывается и как они отображаются. Часто встречающийся случай - подсчёт налогов, добавление скидок, а также стоимость доставки и комиссии при оплате и т. д.
Вместо реализации каждого возможной комбинации для всех этих случаев, django-SHOP предлагает API, где сторонние приложения работают на каждом шаге вычисления. Стоит заметить, модификаторы корзины не только вызываются, когда корзина наполнена и покупатель хочет перейти к оплате, но и для каждого товара перед добавлением в корзину.
Это позволяет программистам изменять цену определённых элементов в зависимости от текущего состояния корзины. Например, можно установить одну цену для первого товара, а затем устанавливать другую цену для каждого последующего добавленного товара в корзину.
Модификаторы корзины разделяются на три различные категории: Общие, Оплата и Доставка. В settings.py они должны быть сконфигурированы как список или тапл такой как:
SHOP_CART_MODIFIERS = ( 'shop.modifiers.defaults.DefaultCartModifier', 'shop.modifiers.taxes.CartExcludedTaxModifier', 'myshop.modifiers.PostalShippingModifier', 'shop.modifiers.defaults.PayInAdvanceModifier', 'shop_stripe.modifiers.StripePaymentModifier', )
Основные модификаторы применяются всегда. Модификаторы доставки и оплаты применяются только для выбранного метода доставки и/или оплаты. Если покупатель ещё не решил, как будет доставлять или как принимать оплату, то соответствующие модификаторы не стоит применять.
При обновлении корзины, модификаторы применяются в порядке приведенного выше списка. Поэтому существует различие, если налоги применяются до или после нанесения стоимости доставки.
Кроме того, всякий раз, когда в карточке товара изменяется количество товара, то все модификаторы запускаются для этого элемента. Это позволяет ItemModelSerializer даже изменить цену продукта в зависимости от общего содержания корзине.
Модификаторы корзины легко создаются и обычно состоят из нескольких строк кода. В django-SHOP такие плагины создают эко-систему. Кроме вычисления общей суммы, модификаторы корзины также могут быть использованы для подсчёта суммы веса, если модели продуктов содержат поле "Вес".
Вот неполный список некоторых полезных модификаторов корзины:
9.4.1. Основные модификаторы корзины
Эти виды модификаторов козины обычно применяются к корзине. Типичным примером может служить DefaultCartModifier, CartIncludeTaxModifier или CartExcludeTaxModifier.
9.4.1.1. DefaultCartModifier
shop.modifiers.default.DefaultCartModifier практически всегда требуется для любой корзины. Он обрабатывает базовые вычисления, а именно подсчёт стоимости элементов корзины, умножая их на добавленное в корзину количество соответственно. Так как модификаторы устанавливают подитог для элементов корзины, поэтому этот модификатор должен стоять на первом месте в списке SHOP_CART_MODIFIERS.
9.4.1.2. Корзинный модификатор оплаты
Эти виды модификаторов применяются только при выборе способа оплаты. Модификаторы оплаты используются для добавления дополнительных расходов или скидок в зависимости от выбранного способа оплаты. Переопределелив метод is_disabled, вы можете отключить способ оплаты. Это бывает полезно в том случае, если сумма платежа ниже некоторого минимального значения.
9.4.1.3. Корзинный модификатор доставки
Эти виды модификаторов применяются только при выборе способа доставки. Модификаторы доставки применяются для добавления дополнительных расходов или скидок в зависимости от выбранного способа доставки, количества элементов в корзине или их веса. Переопределелив метод is_disabled, вы можете отключить способ доставки. Это бывает полезно в том случае, если сумма платежа ниже некоторого минимального значения или вес больше допустимого.
9.4.1.4. Как работают модификаторы
Корзинные модификаторы наследуются от класса shop.modifiers.base.BaseCartModifier и расширяют данные методы:
До django-SHOP версии 0.2 включительно Модификаторы корзины возвращали количество и название для дополнительной строки элемента, а затем django-SHOP добавлял их. Начиная с версии 0.3 модификаторы корзины должны изменять подитог и всю стоимость корзины.
class shop.modifiers.base.BaseCartModifier(identifier=None)
Модификаторы корзины это аналог корзинного бэкенда.
Это позволяет осуществлять налоги и скидки / оптовые цены элегантным способом, который можно многократно использовать. Каждый раз, когда корзина обновляется (через метод update()), вызываются модификаторы корзины добавленные в settings.SHOP_CART_MODIFIERS. в этот список добавляются полные пути до модификаторов.
Вызов методов модификаторов определяются в следующей последовательности:
- pre_process_cart: Общая стоимость не подсчитывается, корзина считается "сырой": доступны только связи и количества.
- pre_process_cart_item: Стоимость элементов не подсчитывается, корзина и его элементы считаются "сырыми": доступны только связи и количества.
- process_cart_item: Вызывается для каждого cart_item в корзине. Модификатор может изменить сумму в cart_item.line_total.
- add_extra_cart_item_row: Опционально добавляет объект типа ExtraCartRow в текущий элемент корзины. Этот объект добавляет дополнительную информацию, которая отображает каждый подитог элемента корзины.
- process_cart: Вызывается для всей корзины. Здесь заполняются все поля, которые относятся к элементам корзины, а также подитоги корзины используются для подсчёта общей суммы корзины.
- add_extra_cart_row: Опционально добавляет объект типа ExtraCartRow в текущую корзину. Этот объект добавляет дополнительную информацию, которая отображается в футер-секции корзины.
- post_process_cart: Все суммы подсчитаны, а корзина готова быть отображенной. Любые изменения сделанные тобой должны быть консистентны!
Каждый метод принимает объект HTTP запроса (HTTP request). Он должен использоваться, чтобы определить их цену в соответствии с сессией, а также другой информацией запроса.
add_extra_cart_item_row(cart_item, request)
Опционально добавляет ExtraCartRow объект в текущий элемент корзины.
Позволяет добавлять дополнительное описание строки в линию элемента корзины. Этот метод опционально использует и/или модифицирует сумму в cart_item.line_total.
add_extra_cart_row(cart, request)
Опционально добавляет ExtraCartRow объект в текущую корзину.
Позволяет добавлять дополнительное описание строки в корзину. Этот метод опционально использует cart.subtotal и/или модифицирует сумму в cart.total.
arrange_cart_items(cart_items, request)
Упорядочивает все элементы, которые предназначены для корзины. Переопределив этот метод, можно отсортировать или перегруппировать возвращаемые элементы.
arrange_watch_items(watch_items, request)
Упорядочивает все элементы, которые находятся в списке просмотренных товаров. Переопределив этот метод, можно отсортировать или перегруппировать возвращаемые элементы.
post_process_cart(cart, request)
Этот метод будет вызываться после того, как корзина была обработана в обратном порядке зарегистрированных модификаторов корзины. Объект Корзина является "финальной" и все поля подсчитаны. Запомните, что все изменения в этой точке должны быть консистентны: Например, если вы хотите обновить цену, которую вы должны также обновить все соответствующие суммы.
pre_process_cart(cart, request)
Этот метод вызывается перед Корзиной, которая начинает подсчитываться. Его следует использовать для вычисления корзины с начальными значениями, но не для подсчёта суммы корзины.
pre_process_cart_item(cart, item, request)
Этот метод вызывается для каждого элемента перед тем, как Корзина начинает подсчитываться. Его следует использовать для подсчёта элемента корзины с начальными значениями, но для подсчёта подитога элемента.
process_cart(cart, request)
Вызывается один раз к Корзине после того, как каждая позиция была обработана методом process_cart_item.
Подитог для корзины уже известен, но общая стоимость корзины всё ещё не известна. Подобно для элементов, сумма ожидается быть подсчитанной первым модификатором корзины, который обычно является DefaultCartModifier. Постмодификаторы опционально можгут изменить общее количество и добавить дополнительную информацию к корзине с помощью объекта типа ExtraCartRow.
process_cart_item(cart_item, request)
Вызывается для каждого элемента в корзине: Элементы обычно содержат: продукт, стоимость продукта, количество и словарь с дополнительной информацией строки.
При соответствующей настройке, общая стартовая линия для каждой строки (цена * количество) вычисляется с помощью DefaultCartModifier, который обычно указан в качестве первого модификатора. Постмодификаторы опционально могут изменить общую корзину позиций.
После обработки всех элементов корзины со всеми модификаторами, эти строки-подитоги суммируются для формирования промежуточной суммы корзины, которая используется методом process_cart.
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0