Найти в Дзене
Logonok

Система онлайн заказа такси

Сегодня расскажу про создание многопользовательской системы услуг такси. Итак, краткое описание базового функционала. Пользователь регистрируется в системе как пассажир (клиент) и создает заказ на поездку, в котором указывает начальный и конечный пункт, дату поездки, желаемую стоимость и т.п. Другие пользователи, зарегистрированные как водители, получают уведомление о новом заказе и могут откликнуться, создав предложения, в которых указывают свою цену поездки и дополнительную информацию. Если клиент принимает одно из предложений, то сделка сделка вступает в силу. Для создания приложения воспользуемся декларативным фреймворком Evado, который позволяет описывать сущности и отношения между ними через веб-интерфейс, тем самым минимизируя написание кода. В окружении фреймворк использует бесплатные веб-сервер Node.js и базу данных MongoDB. Устанавливаем и запускаем шаблон приложения как описано в инструкции. Создание метаданных Метаданные - это описание сущностей приложения, их предста
Оглавление

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

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

Для создания приложения воспользуемся декларативным фреймворком Evado, который позволяет описывать сущности и отношения между ними через веб-интерфейс, тем самым минимизируя написание кода. В окружении фреймворк использует бесплатные веб-сервер Node.js и базу данных MongoDB.

Устанавливаем и запускаем шаблон приложения как описано в инструкции.

Создание метаданных

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

Метаданные сущностей системы заказа такси
Метаданные сущностей системы заказа такси

Переходим в модуль Студия и создаем класс Клиент (client), который описывает клиента (пассажира). Добавляем строковый атрибут Имя (name) и атрибут Пользователь (user) для привязки к системному пользователю. Указываем шаблон заголовка ".name". Шаблон формирует строковое отображение объекта (по умолчанию - это идентификатор объекта).

Точно также создаем класс Водитель (driver).

Далее создаем класс Заказ (order), который описывает требования для поездки. Добавляем строковые атрибуты Начальный пункт (start) и Конечный пункт (end). Добавляем целочисленный атрибут Цена (price) для указания желаемой стоимости поездки. Создаем текстовый атрибут Информация (info) для дополнительной информации. Добавляем ссылочный атрибут Клиент (client) для хранения того, кто создал заказ.

Создаем класс Предложение (offer), который описывает отклик водителя на заказ. Добавляем ссылочный атрибут Заказ (order) для хранения ссылки на заказ, к которому относится предложение. Добавляем атрибуты Цена (price) для задания стоимости поездки и Дополнительная информация (info). Еще добавляем ссылочный атрибут Водитель (driver) для хранения того, кто создал предложение.

Обратные ссылки

Для получения всех заказов пользователя переходим в класс Клиент и создаем атрибут Заказы (orders) с типом обратная ссылка. Указываем ссылочный класс Заказ и ссылочный атрибут Клиент.

В отличие от ссылочного типа, значения обратных ссылок не хранятся в базе, а вычисляются на основе заданного отношения.

Для получения всех предложений водителя переходим в класс Водитель и создаем обратную ссылку Предложения (orders) с ссылочным классом Предложение и ссылочным атрибутом Водитель.

Переходим в класс Заказ и создаем обратную ссылку Предложения (offers) для получения всех предложений, относящихся к заказу (ссылочный класс Предложение и ссылочный атрибут Заказ). Также создаем обратную ссылку Активное предложение (offer) и указываем фильтр { "_state": "inProgress"}, который выбирает из всех предложений только одно в состоянии "В процессе выполнения".

Состояния объектов

Состояния позволяет динамически изменять поведение некоторых объектов одного класса. Вместе с переходами (см. далее) они определяют бизнес-процессы приложения.

Кодовое название состояние храниться в служебном атрибуте _state. Служебные атрибуты сохраняются в объекте вне зависимости от созданных метаданных, но для отображения на форме или в списке они должны быть явно определены. Название служебных атрибутов начинается с подчеркивания:

  • _class - кодовое название класса объекта;
  • _createdAt - дата создания объекта;
  • _creator - пользователь создавший объект;
  • _editor - последний пользователь изменивший объект;
  • _state - кодовое название состояния объекта;
  • _updatedAt - дата последнего изменения объекта.
-3

В классе Заказ создаем возможные состояния заказа:

  • Черновик (draft) - заказ в процессе создания клиентом;
  • Ожидание (waiting) - заказ создан и ожидает предложений от водителей;
  • В процессе (inProgress) - заказ в процессе выполнения;
  • Отменено (cancelled) - клиент отменил заказ;
  • Закрыто (closed) - заказ завершен.

Далее переходим в класс Предложения и создаем состояния для предложений:

  • Новое (new) - новое предложение (по умолчанию);
  • Принято (accepted) - предложение принято клиентом;
  • В процессе (inProgress) - в процессе выполнения;
  • Отменено (cancelled) - предложение отменено водителем;
  • Закрыто (closed) - предложение закрыто водителем.

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

Переходы состояний

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

Переходим в класс Заказ и создаем следующие переходы:

  • Готово (ready) из состояния Черновик в Ожидание.
  • Редактировать (edit) из состояния Ожидание в Черновик.
  • Закрыть (close) из состояния В процессе в Закрыто.
  • Отменить (cancel) из состояния В процессе в Отменено.

Переходим в класс Предложение и создаем следующие переходы:

  • Принять (accept) из состояния Новое в Принято.
  • Подтвердить (confirm) из Принято в состояние В процессе.
  • Закрыть (close) из состояния В процессе в Закрыто.
  • Отменить (cancel) из состояния В процессе в Отменено.

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

Затем добавляем к переходу Редактировать конфигурацию создания объекта транзита:

Настройка дополнительных действий при выполнении перехода
Настройка дополнительных действий при выполнении перехода

Представления класса

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

Переходим в класс Клиент и создаем представление Публичное (public) для отображения клиентов другим пользователям системы. Добавляем атрибуты Имя и Пользователь. Чтобы пользователь не мог изменить данные через это представление, ставим флажок Только для чтения.

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

Переходим в класс Заказ и создаем представление Ожидающий заказ (waitingOrder). В состоянии Ожидания нельзя изменять данные заказа, поэтому ставим флажок Только для чтения. Для показа заказов только в состоянии Ожидания создаем представление Ожидающие заказы (waitingOrders) и указываем фильтр {"_state": "waiting"}. Теперь в списке с данным представлением будут отображаться заказы только в статусе Ожидание.

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

В режиме development в боковое меню модуля Офис выводится служебный пункт _classes, который содержит ссылки на все классы приложения.

Создаем секцию навигации Основная (main). Секция с данным кодовым именем используется для формирования бокового меню в модуле Офис. Переходим в секцию и добавляем пункт Ожидающие заказы (waitingOrders). Указываем класс Заказы и представление Ожидающие заказы.

Экспортируем созданные метаданные в папку приложения (metadata/app).

Безопасность доступа

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

Переходим в модуль Администрирование - Безопасность - Роли и создаем роли - Клиент (client) и Водитель (driver). Каждой из них даем разрешение на доступ к модулю Офис.

Переходим в Разрешения метаданных и создаем разрешение ролям Клиент и Водитель читать представление Публичное класса Заказ.

Для водителей

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

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

Разрешаем водителю читать и изменять только собственные предложения. Для этого добавляем правило Creator, проверяющее является ли пользователь создателем объекта.

Для клиентов

Первым делом разрешаем клиентам создавать заказы, а также читать и изменять собственные заказы. Для этого добавляем правило Creator. Разрешаем удалять только собственные заказы в статусах Черновик или Ожидание. Для этого добавляем правило OrderDeletionRule:

Разрешаем клиенту читать только те предложения, который относятся к его заказам. Для этого добавляем правило ClientOfferRule:

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

Уведомления

Переходим в модуль Администрирование в меню Информирование - Уведомления. Создаем уведомление Новый заказ (newOrder). В поле Тема указываем - newOrder.subject. В поле Текст - newOrder.text. Эти значения являются ключами, которые позволяют генерировать сообщения на разных языках. Фактические значения темы и текста задаются в файле перевода (например, message/notification/ru.js):

'newOrder.subject': 'Новый заказ',
'newOrder.text': 'Заказ от клиента {model.user.getTitle} ожидает

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

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

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

Далее нужно привязать генерацию сообщения к событию создания заказа. Для это переходим в меню События - Слушатели и создаем слушателя для события meta.base.transit.order.ready:

  • meta - событие порождается на основе метаданных;
  • base - название метаданных (base - основные данные, navigation - навигация);
  • transit - событие перехода;
  • order - кодовое имя класса;
  • ready - кодовое имя перехода.

Добавляем уведомление Новый заказ как реакцию слушателя на событие о готовности заказа.

Слушатель события нового заказа
Слушатель события нового заказа

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

Кастомизация интерфейса

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

Кастомизированный интерфейс
Кастомизированный интерфейс

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

Готовое приложение онлайн заказа такси доступно для изучения и модификации.