Найти тему
Logonok

Как создать товар, состоящий из других товаров

Оглавление

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

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

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

Метаданные

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

Сущность «Товар»

Создаем класс Товар, который будет описывать одноименную сущность. Добавляем атрибуты класса - Название, Описание, Цена, Запас, которые есть у любого товара в магазине.

Для того, чтобы создать товар, состоящий из других товаров, добавим еще несколько атрибутов. Логический атрибут Набор товаров определяет, что товар состоит из других товаров. Ссылочный атрибут Товары набора содержит ссылки на товары, входящие в набор.

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

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

Настройки действий отрабатывают на форме клиента непосредственно в момент ввода данных.

Сущность «Заказ»

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

Служебные атрибуты хранятся в объекте вне зависимости от наличия метаданных и доступны только для чтения.

Для того, чтобы в одном заказе могли находиться сразу несколько товаров в разном количестве, опишем новую сущность - Элемент заказа. Добавляем в нее ссылочные атрибуты на Заказ и Товар, вещественный атрибут Цена и целочисленный Количество.

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

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

Далее создаем простейший бизнес-процесс заказа.

Переход - это способ изменения состояния объекта
Переход - это способ изменения состояния объекта
Бизнес-процесс определяет различные состояния и способы их обработки (переходы) для однотипных объектов.

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

Дополнительный функционал

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

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

Корзина пользователя

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

До заказа корзина хранится в браузере покупателя
До заказа корзина хранится в браузере покупателя

Переходим в класс Заказ и создаем представление Создание из корзины. Подключаем к представлению поведение CartOrderBehavior, создающее объекта заказа по данным корзины пользователя (в том числе проверяющее эти данные на корректность).

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

Переходим в модуль Администрирование в раздел Безопасность - Разрешения метаданных и добавляем разрешение на создание для представления Создание из корзины.

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

Заключение

Готовый магазин доступен в открытом репозитории.

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