Веб-приложение для заказа из ресторана по QR-коду
Общие положения по работе веб-приложения
Внедрение ПО (программного обеспечения), которое позволит оформить заказ блюд через мобильный телефон гостя из меню ресторана, оплатить заказ и при необходимости применить корпоративную скидку. ПО должно распечатать заказ на кухню и бар. Менеджер ресторана должен иметь понятный интерфейс для работы с меню (добавление, удаление, корректировку цен и т.п.). В ПО надо учесть, что точка питания будет готовить часть продуктов на вывоз (Яуза).
Все изображения приведены для примера и не содержат обязательных требований, если иное не отражено в тексте ТЗ.
Экономическое обоснование
Внедрение системы позволяет значительно снизить нагрузку на официантов, т.к. оформление заказа и его оплата выполняются гостем самостоятельно. Уменьшаются требования к официантам, поскольку им теперь нужно учить меню, да и навыки общения с гостями уже нужны не такие высокие.
Кроме того, повышается комфорт гостя, поскольку больше не нужно ожидать официанта чтобы оформить и оплатить заказ, или заказать что-то ещё. А для применения скидок не нужно сообщать официанту свой номер телефона.
Особенно удобно такое приложение для организации корпоративного питания, когда происходит идентификация посетителя и автоматическое предоставление предусмотренных договором скидок. При этом сохраняется возможность загрузки списка сотрудников из 1С, настройка различных дисконтных схем и формирования отчётов и счетов для контрагентов.
Также приложение предусматривает возможность начисления бонусов на заказы. В перспективе возможна несложная доработка возможности оплачивать часть заказа бонусами.
Экономический эффект достигается за счёт:
-
- Сокращения количества официантов (минимум одного в смену) и уменьшение требований к ним.
- Увеличения среднего чека, т.к. гостю легко сделать больший заказ или дозаказать блюдо - отсутствует барьер в виде необходимости ждать официанта.
- Увеличение посещаемости за счёт привлечения сегмента корпоративного питания и общего увеличения комфорта гостей.
Таким образом, общий экономический эффект можно оценить от 100 000 руб в месяц на каждый ресторан.
Описание требований к программному обеспечению
- Программное обеспечение должно работать на WEB платформе
- ПО должно легко масштабироваться и принимать нужный формат исходя из разрешения экрана и особенностей мобильного телефона (браузеров)
- Серверное программное обеспечение должно обрабатывать до 200 заказов единовременно
- Оплата заказа должна производиться сразу, после оформления заказа. Оплата производится через систему ЮKassa
- Фискальный чек выдается системой ЮKassa в электронном виде
- Применение корпоративных скидок будет осуществляться на базе существующих разработок, идентификация клиента будет производиться по номеру телефона
- В веб-приложении будет задействовано актуальное меню ресторана, но в меню могут быть позиции, которые нельзя будет заказать через веб-приложение.
Принципиальная схема работы
- Сканирование QR-кода
- Выбор блюд из меню
- Проверка и корректировка заказа
- Регистрация клиента (сотрудника). Если не был ранее сохранён в приложении
- Расчёт всех скидок, согласно настройкам в системе Юпитер
- Оплата заказа (ЮKassa)
- Создание заказа в системе Юпитер и отправка заказа на выполнение
- Завершение работы приложения
Архитектура системы
- Сервер ресторана (сервер Юпитер)
- Расположен непосредственно в ресторане
- Имеет доступы ко всем принтерам в ресторане
- Имеет белый ip для доступа из сети Internet
- Протокол HTTP
- Порт 7788
- Веб-сервер
- Размещается на хостинге
- Доменное имя любое
- Протокол HTTPS
- Веб-приложение
- Открывается на телефоне клиента через сканирование QR-кода.
- Отображает меню, позволяет оформить заказ
- Позволяет получить скидки (в т.ч. корпоративную скидку сотрудника)
- Позволяет оплатить заказ
- Передаёт заказ на выполнение в систему Юпитер.
Меню
Структура меню
- Меню представляет собой список групп и вложенных в них товаров (группа - товар). Вложенность групп друг в друга не предусмотрена
- Один товар может относится только к одной группе
- У товаров могут быть модификаторы (товары, дополняющие базовый товар – например состав бизнес-ланча)
- Модификаторы не имеют цены (на первом этапе разработки, в дальнейшем можно будет добавить эту логику работы в рамках отдельной задачи)
- Модификаторы сгруппированы по группам модификаторов внутри базового товара (например, для бизнес-ланча: «Салат», «Первое блюдо», «Горячее», «Напиток»)
- Из каждой группы модификаторов можно выбрать только один модификатор, т.е. нельзя выбрать два супа или два напитка
- Группы модификаторов могут быть
- Обязательные - в которых необходимо сделать какой-то выбор, чтобы добавить бизнес-ланч в корзину.
- Необязательные - где выбор не обязателен
- В рамках данного ТЗ все группы модификаторов считаются обязательными
- Товары с модификаторами могут быть в любой группе. Для удобства пользователей первая отображаемая группа может быть названа «Бизнес-ланч» и содержать все действующие сегодня бизнес-ланчи. Бизнес-ланчей в рамках одного дня может быть несколько – за разную стоимость и с разным составом.
Обновление меню
- Меню приложения автоматически обновляется Юпитером каждый час, чтобы учесть возможные автоматические изменения меню по расписанию.
- При необходимости, меню в приложении также можно обновить вручную из складской части Юпитера на сервере ресторана
- Меню веб-приложения формируется по тем же раскладкам меню, которые используется на кассе в этом ресторане
- У пользователя есть возможность отключить передачу отдельных кнопок раскладки в веб-приложение, если какие-то блюда не должны быть в меню приложения.
- Иерархия раскладок принудительно приводится к двухуровневой структуре (группа - товар)
- Если товар присутствует на нескольких раскладках, то в веб-приложение он будет передан только по первой раскладке
- Если на самом первом уровне меню будут занесены товары, они будут игнорироваться (на первом уровне должны быть группы товаров, а не сами товары)
- Список товаров для меню формируется с учётом расписания замен раскладок
-
- При настройке расписания замен нужно учитывать, что меню в веб-приложении обновляется 1 раз в час
-
- Меню для приложения берётся с текущего рабочего меню кассы, которое появляется в системе после выполнения действия "Обновить меню на кассах". Т.о. можно внести изменения в меню и они не будут переданы на приложение, пока меню не будет актуализировано для ресторана в целом.
Фотографии
- В качестве фотографий в веб-приложении используются картинки заданные на кнопках в раскладках меню. Те же, что и для кассы
- Картинки товаров привязываются к товарам в системе Юпитер и хранятся в специальной папке со специальными именами.
- Для обновления фотографий в веб-приложении, требуется вручную загрузить новые файлы из этой папки на сервер веб-приложения (через техподдержку). Предполагается, что фотографии блюд меняются достаточно редко. В дальнейшем можно будет реализовать автоматическую загрузку (в рамках отдельной задачи).
Стоп-лист
- Стоп-лист формируют на кассе вручную
- Меню доступное в веб-приложении формируется с учётом текущего стоп-листа
- Если товар добавят в стоп-лист в момент, когда клиент уже начал оформлять заказ, то этот товар будет доступно для заказа. При переходе в режим оплаты клиенту будет выведено сообщение о том, что товар из корзины более не доступен для заказа
- На кассе могут указать "Оставшееся кол-во" для одного или нескольких товаров. Когда "Оставшееся кол-во" будет распродано, товар автоматически добавится в стоп-лист
- Веб-приложение не контролирует "Оставшееся кол-во" в процессе ввода заказа, контроль будет происходить при переходе в режим оплаты
- Если клиент заказал больше чем "Оставшееся кол-во" у одного или нескольких товаров, ему будет выведено сообщение с наименованиями этих товаров
- В конце рабочего дня все оставшееся кол-во для всех товаров обнуляется
- Веб-приложение не контролирует "Оставшееся кол-во" в процессе ввода заказа, контроль будет происходить при переходе в режим оплаты
Маркированный и подакцизный товар (Честный знак, ЕГАИС)
- В программе должна быть возможность исполнения требований государства по работе с кодами маркировки (КМ) и акцизными марками (АМ) в заказах оформленных в веб-приложении
- Заказы, в которых есть алкоголь или маркированные товары, не должны закрываться пока в них не будут считаны все КМ или АМ
Корпоративные клиенты и скидки
-
- Основное принцип – Юпитер должен применить к заказу с веб-приложения все те же скидки, как будто бы этот заказ оформили на станции кассира
- Все автоматические скидки
- Настройка "Когда применять автоматическую скидку" игнорируется
- Если используются скидки по расписанию, то "Способ определения скидки" должен быть всегда "Время открытия заказа"
- Скидки клиента. Если клиент определен
- Подарочные товары не применяются
- Бонусная система (кэшбек) через веб-приложение может работать только в режиме начисления бонусов. Потратить бонусы пока можно только через официанта
- Все автоматические скидки
- «Корпоративные клиенты» — это скидка для действующих сотрудников, которая уже внедрена и работает по алгоритму (например, скидка 90% от базовой ставки 500 рублей). Базы данных, структура обмена и отчетов остаются прежними. Идентификация клиента в корпоративной скидке будет являться номер телефона клиента, который он зафиксировал в договоре о корпоративном питании.
- Основное принцип – Юпитер должен применить к заказу с веб-приложения все те же скидки, как будто бы этот заказ оформили на станции кассира
Кухня (взаимодействие)
После того, как заказ оплачен и создан в системе Юпитер, дальнейшая работа с заказом происходит стандартным образом в соответствии с настройкой системы Юпитер. Заказ печатается на нужных кухонных принтерах, выполняется кухней, собирается по чеку сборки. При необходимости печатается счёт, и официант относит заказ на стол гостям вместе со счётом. Счёт может быть полезен, чтобы гости могли ещё раз проверить сумму заказа и какие скидки были применены.
Общий зал и VIP зал (взаимодействие)
В общем зале, банкетном зале буду стоят дополнительные моноблоки для оформления заказов официантами вручную, которые будут автоматически уходить на кухню или в бар, в зависимости от состава. (Аналог работы кафе «Чайка»).
Вопросы безопасности
- Чтобы не могли получить скидку за счёт другого клиента.
- Для этого авторизация клиента происходит через SMS с проверочным кодом, чтобы никто не мог воспользоваться тем, что знает номер телефона другого клиента
- SMS отправляется через сервис https://stream-telecom.ru/
- Проверочный код состоит из 5 цифр
- Для защиты от подбора проверочного кода сервер позволяет только три попытки его ввода
- Срок жизни проверочного кода 3 минуты. Т.е. после запроса проверочного кода, у клиента будет 3 минуты, чтобы получить SMS и ввести код
- Запросить проверочный код можно не чаще чем 1 раз в 5 минут
- После успешного оформления заказа клиенту на телефон приходит SMS с информацией, что по его номеру телефона оформлен заказ на такую-то сумму
- Для этого авторизация клиента происходит через SMS с проверочным кодом, чтобы никто не мог воспользоваться тем, что знает номер телефона другого клиента
- Чтобы не могли сделать заказ по неверной цене (хакнув приложение или перехватив запрос)
- Юпитер, получив заказ, берёт не те цены, которые пришли из приложения, а те цены, которые установлены в системе Юпитер. От них считаются и скидки, и сумма к оплате. Таким образом, подмена цен в запросе ничего не даст. Заказ всегда будет создан на правильную сумму.
- Проверка подлинности уведомлений
- Нужно проверять уведомление об успешном платеже от ЮKassa на подлинность
- Рекомендации ЮKassa
Веб-приложение
Начало работы
- Клиент своим телефоном сканирует QR-код, размещённый на столике в заведении
- В QR-коде закодирована ссылка на
веб-приложение
, которая открывается в браузере на телефоне клиента- Пример ссылки в QR-коде:
https://site.ru/?token=9990775155c3518a0d7917f7780b24aa
- В URL содержатся
Токен авторизации
- По
Токену авторизации
система будет определять для какого стола и в каком ресторане формируется заказ -
Токен авторизации
создается и регистрируется специалистами технической поддержки системы Юпитер
- По
-
Токен авторизации
должен передаваться во всех запросах от веб-приложения к веб-серверу, через заголовокX-Jup-Api-Key
- Веб-приложение должно получить
Токен авторизации
из URL и сохранить локальное хранилище- По возможности, после сохранения
Токена авторизации
, веб-приложение должно удалить токен из URL (window.location.replace
), чтобы в истории браузера URL сохранился без токена. Это нужно, чтобы запретить вход в веб-приложение из истории браузера, без сканирования QR.
- По возможности, после сохранения
- Пример ссылки в QR-коде:
- На один стол можно одновременно оформлять несколько заказов, например если за столом несколько гостей.
- Когда
веб-приложение
открывается в браузере, оно выполняет следующие действия:- Отправляет на сервер запрос
/start
, в ответ получает:- Уникальный идентификатор сессии,
session_id
-
session_id
в дальнейшем всегда передаётся во всех запросах серверу, в заголовкеX-Jup-Session-Id
-
- Название организации и ресторана (на двух языках)
- Актуальное меню для этого ресторана (на двух языках)
- Уникальный идентификатор сессии,
- Если клиент авторизован в
веб-приложении
, то в запросе серверу также передается идентификатор клиентаclient_id
- Получив
client_id
, сервер проверит, что в системе существует клиент с таким идентификатором - Если клиента не существует, то сервер вернет в ответе параметр
client_verified
= false. Это означает, что клиент не авторизован и веб-приложение отменит текущую авторизацию- Удалит
client_id
из LocalStorage
- Удалит
- Получив
- Если ответ от сервера не получен, выдаёт сообщение об ошибке
- Открывает меню (menu_view) – по умолчанию на русском языке
- Отправляет на сервер запрос
Страница с меню (menu_view)
Рис. 1
- Страница с меню (menu_view) является основным интерфейсом приложения
- В самом верху экрана находится системная зона - узкая полоска, содержащая:
- Название организации
- Иконки (флаги) выбора языка интерфейса и меню – русский и английский
- При нажатии на флаг система заменяет все названия на названия на выбранном языке
- Кнопка профиля клиента. Открывается окно авторизации (client_auth)
- Вверху экрана находится зона с кнопками выбора категорий (header)
- Зона закреплена от вертикальной прокрутки
- Зона имеет горизонтальную прокрутку для размещения большего числа кнопок, чем помещаются по ширине экрана.
- Внизу экрана расположена зона итогов (footer), где находятся:
- Сумма заказа
- Кнопка «К заказу» (to_cart_button)
- Зона footer закреплена от вертикальной прокрутки. Чтобы клиент всегда видел актуальную сумму своего выбора
- Между зонами header и footer расположен список блюд из выбранной категории
- Каждое блюдо выводится в отдельной карточке (см. рис. 1)
- Карточки блюд выводятся одной колонкой
- Карточка блюда занимает всю ширину экрана
- В карточке блюда отображаются
-
- Фотография блюда
- Название блюда
- Вес порции
- Цена
- Кнопка добавления в корзину
-
- При нажатии на кнопку добавления в корзину
- Если блюдо имеет модификаторы, то открывается модальное окно выбора модификаторов (modif_view)
- Если блюдо не имеет модификаторов, оно просто добавляется в список выбранных (в корзину)
- Вместо кнопки добавления в корзину, отображаются кнопки изменения количества «+» [текущее кол-во] «-»
- Пересчитывается итог по заказу в зоне footer
- При нажатии на кнопку увеличения количества «+»
- Если у блюда нет модификаторов, то просто увеличивается количество блюда в корзине и текущее кол-во увеличивается на 1
- Если у блюда есть модификаторы (бизнес-ланч), то предполагается, что клиент выбирает ещё один бизнес-ланч и отображается модальное окно выбора модификаторов (modif_view)
- После закрытия окна modif_view отображается общее количество таких блюд в корзине (с любыми модификаторами). Т.е. если блюдо называлось «Бизнес-ланч №1», то просто будет количество 2, даже если выбран разный состав. Увидеть бизнес-ланчи разного состава по отдельности можно будет в корзине. Как работает такая логика можно посмотреть на сайте https://shoko.ru/
- При нажатии на кнопку уменьшения количества «-»
- Если товар без модификаторов, то его количество в корзине уменьшается на 1
- Если товар с модификаторами, то из корзины удаляется последний добавленный товар с его модификаторами
- Если новое количество 0, то вместо кнопок изменения количества отображается кнопка добавления в корзину
- При нажатии на карточку блюда (не на кнопку добавления в корзину) открывается модальное окно с описанием блюда (item_view)
Окно выбора модификаторов (состава бизнес-ланча) (modif_view)
- Выводится в модальном режиме
- В окне размещены
- Название базового товара (бизнес-ланча)
- Цена базового товара
- Составляющие товара (бизнес-ланча) в виде групп radio-button (выбор только одной позиции из группы)
- В строке модификатора отображается:
- Иконка выбора (кружочек)
- Название модификатора.
- Иконка получения информации о компоненте, при нажатии на которую открывается item_view.
- При нажатии на на название модификатора происходит его выбор (в кружочке появляется точка)
- Внизу окна (footer) размещена кнопка
- «Подтвердить», при нажатии на которую:
- Базовый товар (бизнес-ланч) добавляется в корзину со всеми выбранными модификаторами. При добавлении в корзину товары с одинаковыми модификаторами группируются в одну строку, товары с разными модификаторами оказываются в разных строках корзины. Модификаторы при добавлении в корзину сортируются по порядку следования групп модификаторов при выборе (модификатор из первой группы идёт первым, из второй – вторым и т.д.).
- Окно выбора модификаторов
- Бизнес-ланч сохраняется в корзину вместе со всеми выбранными компонентами
- Общая сумма заказа пересчитывается
- «Отменить», при нажатии на которую:
- Окно выбора бизнес-ланча закрывается
- В корзине ничего не меняется
- Общая сумма заказа не пересчитывается
- «Подтвердить», при нажатии на которую:
Окно описания блюда (item_view)
Рис. 2
- Выводится в модальном режиме
- Нажатие кнопки "Назад" в браузере, должно закрывать модальное окно
- В окне размещены
- Фотография блюда
- Название блюда
- Описание блюда
- Цена блюда
- Крестик в верхнем правом углу для закрытия окна
Кнопка «К заказу» (to_cart_button)
При нажатии кнопки «К заказу» (to_cart_button):
- Исчезает зона header выбора категорий, вместо него отображается другой header, содержащий:
- Стрелку влево (возврат в меню)
- Надпись «Проверьте ваш заказ»
- Footer с суммой заказа остаётся и содержит теперь:
- Сумму заказа
- Кнопку «Оплата» (to_payment_button)
- Между ними отображается список товаров из корзины
- Товары без модификаторов показываются в том же формате, как в меню
- Товары с модификаторами показываются в том же формате, в дополнение третьей строкой выводится список названий модификаторов, чтобы клиент видел, что именно выбрано. Модификаторы просто перечисляются строкой (только названия – без цен и количества, поскольку цены нет, а количество всегда 1).
- В этом списке точно также работают кнопки + и – для изменения количества с пересчётом итога.
- Для товаров с модификаторами кнопки + и – влияют на именно на эту строку – именно с этими модификаторами.
- Если количество становится 0, то строка просто удаляется из корзины.
- Изменить выбранные модификаторы нельзя. Можно только добавить ещё один товар с другими модификаторами, а ненужный удалить. Удалить можно либо из меню (нажав «-» - тогда удалится последняя добавленная запись), либо из корзины – явно удалив нужную запись.
Окно авторизации клиента (client_auth)
- Выводится в модальном режиме
- Нажатие кнопки "Назад" в браузере, должно закрывать модальное окно, а не отрабатывать переход на предыдущую страницу
- В окне размещены
- Крестик в правом верхнем углу для закрытия модального окна
- Текст «Укажите номер телефона»
- Поле ввода номера телефона. При вводе номера клиента для удобства должна быть задействована цифровая клавиатура телефона, без букв
- Если клиент уже авторизован, то поле с номером телефона клиента заполнено номером телефона клиента текущего клиента
- Кнопка «Ок» (client_start_check), при нажатии на которую
- Отправляется запрос на сервер
/client_start_check
с введённым номером телефона- Сервер отправляет на этот номер SMS с проверочным кодом
- Сервер может вернуть сообщение об ошибке, которое нужно будет показать в приложении
- Если сервер вернул успех, всё содержимое окна исчезает (кроме крестика) и появляется:
- Текст "Мы отправили SMS с проверочным кодом на телефон [номер телефона]. Введите проверочный код"
- Поле для ввода проверочного кода
- При вводе проверочного кода для удобства должна быть задействована цифровая клавиатура телефона, без букв
- Кнопка «Ок», при нажатии на которую:
- Отправляется запрос на сервер
/client_check
с введённым кодом- Сервер верифицирует проверочный код и возвращает ответ
- Если сервер вернул ошибку, она выводится пользователю, под полем ввода кода
- В случае успеха сервер вернет
client_id
, который сохраняется в LocalStorage браузера и используется в последующих запросах- Признаком, того что клиент авторизован является наличие
client_id
в LocalStorage браузера - Маловероятно, но если зачем-то нужно будет отменить регистрацию клиента, нужно будет почистить кеш браузера
- Признаком, того что клиент авторизован является наличие
- Отправляется запрос на сервер
- Отправляется запрос на сервер
- Кнопка "Отправить код еще раз"
- Делает то же самое, что и кнопка (client_start_check)
Кнопка «Оплата» (to_payment_button)
При нажатии на кнопку «Оплата» (to_payment_button):
- Отправляет запрос серверу на создание предзаказа
/preorder
и получает обратно:- Сумму заказа до скидок
- Сумму всех скидок (одной суммой)
- Итоговую сумму заказа
- Ссылку на оплату в системе ЮKassa
- После получения ответа открывается модальное окно оплаты (payment_view)
Окно оплаты (payment_view)
- Заголовок
- Стрелка влево, которая возвращает в корзину
- В случае возврата в корзину при повторном заходе на страницу оплаты повторяются все те же действия и формируется новая ссылка на оплату.
- Нажатие кнопки "Назад" в браузере, должно также возвращать клиента в корзину
- Надпись «Оплата»
- Стрелка влево, которая возвращает в корзину
- Тело страницы:
- «Сумма заказа:» [Сумма заказа]
- «Скидка:» [Сумма всех скидок]
- «Итого к оплате:» [Сумма к оплате]
- Кнопка «Оплатить» (payment_button) со ссылкой на оплату в системе ЮKassa
- При нажатии на эту кнопку, в этой же вкладке браузера, открывается сайт ЮKassa
- На этом работа с приложением завершается
- Все данные сессии (локальной хранилище), кроме
client_id
, очищаются
- Все данные сессии (локальной хранилище), кроме
- Попав на сайт ЮKassa пользователь совершает оплату удобным ему способом
- Если оплата была успешной, то ЮKassa сообщает об этом клиенту и делает следующее:
-
-
- Отправляет сообщение об успешной оплате серверу. Сервер, получив это сообщение, находит в системе Юпитер, сохранённый на этапе расчёта скидки предзаказ, отмечает его в Юпитере как оплаченный и вызывает действие «Отправить в работу»
- Перенаправляет клиента на фиксированную страницу веб-приложения успешной оплаты (success_payment_view), на которой выводится:
- Текст «Ваш заказ был успешно оплачен и принят в работу»
- Кнопку «Закрыть приложение» при нажатии на которую эта вкладка браузера закрывается.
-
-
Веб-сервер
Авторизация запросов
Трудозатраты: 3
Описание:
- Для реализации данного функционала, на веб-сервере будет развернута база данных (MySQL)
- Таблица "Организации"
- ID
- Название
- Таблица "Торговые залы"
- ID
- ID организации
- Название
- Название на английском языке
- Адрес сервера ресторана
- Текущее меню
- Таблица "Столы"
- ID
- ID торгового зала
- Название (номер)
- Таблица "Организации"
- Во всех запросах к веб-серверу передается
Токен авторизации
через заголовокX-Jup-Api-Key
- Веб-сервер по
Токену авторизации
находит Стол по ID- Если Стол не найдет, то ищет Торговый зал по ID
- Если Стол найден, то определяет к какому Торговому залу он принадлежит
- По Торговому залу устанавливает адрес сервера ресторана
- Если не удалось найти Стол или Торговый зал, то сервер вернет ошибку 401 Unauthorized
Запрос на открытие сессии (/start
)
Трудозатраты: 5
Описание:
- Веб-приложение отправляет запрос на открытие сессии
- Веб-сервер формирует уникальный идентификатор сессии, далее
session_id
- Если передан
client_id
, то отправляет запрос на сервер ресторана/jup/client
для верификации клиента- Если клиента с таким
client_id
не прошел верификацию, то в ответе будет передан параметрclient_verified
= false - В других случаях этот параметр будет иметь значение true
- Если клиента с таким
- Веб-сервер возвращает
- Идентификатор сессии
- Статус верификации клиента
- Наименование торгового зала (на двух языках)
- Текущее меню по торговому залу (на двух языках)
- Меню учитывает текущий стоп-лист торгового зала. Товары которые находятся в стопе не передаются в веб-приложение
- Для этого веб-приложение, перед тем как передавать ответ в веб-приложение, должно убрать из меню все товары, которые есть в стоп-листе
- Меню учитывает текущий стоп-лист торгового зала. Товары которые находятся в стопе не передаются в веб-приложение
Адрес: /start
Метод: GET
. Параметры:
-
client_id
- Не обязательный. Передается если клиент авторизован
Ответ успех:
{
"session_id": "5595236c62914db69d5c07e064530700", // Идентификатор сессии
"client_verified": true, // Статус верификации клиента. Если false, то нужно сбросить авторизацию в веб-приложении
"restaurant": {
"name": "Ресторан № 1", // Наименование торгового зала
"name_eng": "Restaurant № 1" // Наименование торгового зала на английском языке
},
"menu": { // Меню ресторана по концепции
"lastChange": "2024-05-21T16:19:13.000+03:00", // Дата последнего изменения меню, в формате RFC3339
"categories": [ // Список категорий меню
{
"id": "5:3:0:832141", // Идентификатор категории
"name": "Роллы", // Название категории
"name_eng": "Rolls", // Название на английском языке
"sortOrder": 0, // Порядок сортировки от меньшего к большему
"images": [ // Изображение категории
{
"url": "string", // Ссылка на изображение для скачивания
"updatedAt": "2024-05-21T16:19:13.000+03:00" // Дата обновления изображения, в формате RFC3339
}
]
}
],
"items": [ // Список товаров
{
"id": "T20231", // Идентификатор товара
"categoryId": "5:3:0:832141", // Идентификатор категории к которой относится товар
"name": "Филадельфия Гранд", // Название
"name_eng": "Philadelphia Grand", // Название на английском языке
"description": "Рис, нори, сыр сливочный, огурец, лосось. Подается с соевым соусом (30 г), имбирём (30 г), васаби (10 г).", // Описание для меню
"description_eng": "Rice, nori, cream cheese, cucumber, salmon. Served with soy sauce (30 g), ginger (30 g), wasabi (10 g).", // Описание для меню на английском языке
"price": 500, // Цена
"vat": 0, // НДС, включенный в стоимость, в процентах, если не указан, считается за 0
"measure": 240, // Вес или объем
"measureUnit": "г", // Единица измерения. Допустимые значения - граммы (г) и миллилитры (мл)
"sortOrder": 0, // Порядок сортировки от меньшего к большему
"nutrients": [ // Параметры КБЖУ на 100г. Необязательный параметр
{
"calories": 142, // Калории
"proteins": 10, // Белки
"fat": 7, // Жиры
"carbohydrates": 11 // Углеводы
}
],
"modifiers": [ // Группы модификаторов для товара. Необязательный параметр
{
"id": "5:3:0:11821", // Идентификатор группы модификаторов
"name": "Доп. гарниры", // Название группы модификаторов
"name_eng": "Side dishes", // Название на английском языке
"minSelectedModifiers": 0, // Минимальное количество модификаторов, которые необходимо выбрать для данной группы
"maxSelectedModifiers": 3, // Максимальное количество модификаторов, которые можно выбрать для данной группы
"sortOrder": 0, // Порядок сортировки от меньшего к большему
"modifiers": [ // Список модификаторов
{
"id": "6021", // Идентификатор товара-модификатора
"name": "Соевый соус (30 г)", // Название
"name_eng": "Soy sauce (30 g)", // Название на английском языке
"price": 50, // Цена
"vat": 0, // НДС, включенный в стоимость, в процентах, если не указан, считается за 0
"minAmount": 0, // Минимальное количество указанного модификатора для блюда в заказе
"maxAmount": 3, // Максимальное количество указанного модификатора для блюда в заказе
"sortOrder": 0 // Порядок сортировки от меньшего к большему
},
{
"id": "6042",
"name": "Имбирь (30 г)",
"name_eng": "Ginger (30 g)", // Название на английском языке
"price": 50,
"vat": 0,
"minAmount": 0,
"maxAmount": 3,
"sortOrder": 1
}
]
}
],
"images": [ // Изображение товара
{
"url": "https://url.url", // Ссылка на изображение для скачивания
"hash": "55247fb2135f11ef8a4fd00db080bd69" // SHA1-хэш от содержимого файла изображения. Служит признаком уникальности. В случае если он меняется, сайт перезагружает картинку
}
],
"tags": [ // Список тегов товара. Необязательный параметр
{
"name": "Хит" // Название тега
}
]
}
]
}
}
Ответ ошибка:
{
"result": "error",
"desc": "Что-то пошло не так"
}
Создание запроса на авторизацию клиента (/client_start_check
)
Трудозатраты: 1
Описание:
- Веб-приложение отправляет запрос с введённым номером телефона
- Веб-сервер авторизует запрос по
Токену авторизации
- Предаёт запрос на сервер ресторана
/jup/client_start_check
- Запрос обрабатывается сервером ресторана
- Веб-сервер транслирует ответ сервера ресторана веб-приложению
Метод: POST
. Тело запроса:
{
"phone": "79998886655", // Введенный номер телефона. Обязательный
"session_id": "5595236c62914db69d5c07e064530700" // Идентификатор сессии. Обязательный
}
Ответ успех:
{
"result": "success"
}
Ответ ошибка:
{
"result": "error",
"desc": "Повторный запрос кода возможен через 2 мин."
}
Авторизация клиента по проверочному коду (/client_check
)
Трудозатраты: 1
Описание:
- Веб-приложение отправляет запрос с введённым проверочным кодом
- Веб-сервер авторизует запрос по
Токену авторизации
- Предаёт запрос на сервер ресторана
/jup/client_check
- Запрос обрабатывается сервером ресторана
- Веб-сервер транслирует ответ сервера ресторана веб-приложению
Метод: POST
. Тело запроса:
{
"code": "12345", // Введенный проверочный код
"session_id": "5595236c62914db69d5c07e064530700" // Идентификатор сессии. Обязательный
}
Ответ успех:
{
"result": "success",
"client_id": "00000000-0000-0000-9001-000000000805"
}
Ответ ошибка:
{
"result": "error",
"desc": "Введен неверный проверочный код. Осталось попыток: 1"
}
Создание предзаказа (/preorder
)
Трудозатраты: 1
Описание:
- Веб-приложение отправляет запрос на создание предзаказа
- Веб-сервер авторизует запрос по
Токену авторизации
- Предаёт запрос на сервер ресторана
/jup/preorder
- Запрос обрабатывается сервером ресторана
- Веб-сервер транслирует ответ сервера ресторана веб-приложению
Метод: POST
. Тело запроса:
{
"date": "2024-04-08 15:21:03", // Дата\время оформления заказа
"client_id": "00000000-0000-0000-9001-000000000805", // Идентификатор клиента
"cart": { // Содержимое заказа
"items": [ // Товарная часть
{
"id": "T20231", // Идентификатор товара
"count": 1 // Количество
},
{
"id": "555333111",
"count": 3,
"modifiers": [ // Массив вложенных модификаторов к этому товару
{
"id": "6021", // Идентификатор товара
"count": 1 // Количество
},
{
"id": "6042",
"count": 1
}
]
}
]
}
}
Ответ успех:
{
"result": "success",
"pretotal": 5000.00,
"discount": 100.00,
"total": 4900.00,
"confirmation_url": "https://yoomoney.ru/api-pages/v2/payment-confirm/epl?orderId=23d93cac-000f-5000-8000-126628f15141"
}
Ответ ошибка:
{
"result": "error",
"desc": "Что-то пошло не так"
}
Изменение статуса оплаты, от ЮKassa (/payment
)
Трудозатраты: 1
Описание:
- ЮKassa уведомляет веб-сервер об изменении статуса платежа
- Отправляет запрос на URL веб-сервера, в параметрах URL передается
Токен авторизации
- Отправляет запрос на URL веб-сервера, в параметрах URL передается
- Веб-сервер авторизует запрос по
Токену авторизации
- Предаёт запрос на сервер ресторана
/jup/payment
- Веб-сервер транслирует ответ сервера ресторана в ЮKassa
Метод: POST
. Параметры:
- token - Обязательный.
Токен авторизации
Обновить меню, от сервера ресторана (/update_menu
)
Трудозатраты: 1
Описание:
- Сервер ресторана периодически или вручную передает меню в формате JSON
- Веб-сервер по
Токену авторизации
определяет торговый зал - Валидирует и сохраняет полученное меню с привязкой к торговому залу
Метод: POST
Обновить стоп-лист, от сервера ресторана (/update_stop-list
)
Трудозатраты: 1
Описание:
- Сервер ресторана при каждом изменении стоп-листа (в т.ч. автоматическом) передает стоп-лист в формате JSON
- Веб-сервер по
Токену авторизации
определяет торговый зал - Валидирует и сохраняет полученный стоп-лист с привязкой к торговому залу
Адрес: /update_stop-list
Метод: POST
Сервер ресторана (Юпитер)
Меню на двух языках
Трудозатраты: 1
Описание:
- Добавить в Юпитер возможность задавать наименование на дополнительном языке для:
- Наименования торгового зала
- Наименования ТМЦ
- Описания ТМЦ
- Наименования раскладок (разделов меню)
- Наименования групп модификаторов
- Наименования модификаторов
Регистрация торгового зала и столов на веб-сервере
Трудозатраты: 2
Описание:
- Регистрация выполняется вручную администратором сервера веб-приложения (сотрудник Юпитер)
- Для выполнения регистрации сотрудники технической поддержки Юпитер должны представать данные для регистрации
- Чтобы получить данные для регистрации, нужно запустить специальный отчёт из складской части Юпитера "Данные для регистрации в веб-приложении"
- Отчёт запросит торговый зал
- Отчёт выводит
- ID организации (задается в настройках холдинга)
- ID торгового зала (закодированный UID)
- Название торгового зала
- Название торгового зала на английском языке
- Список столов торгового зала
- ID стола (закодированный UID)
- Название (номер)
Выдача URL для QR-кодов
Трудозатраты: 1
Описание:
- Отчёт, который выводит список столов и URL который нужно разместить в виде QR-кода
- Отчёт запросит торговый зал
- Отчёт выводит
- Название торгового зала
- Название стола
- URL для QR-кода
Автоматическая печать на кухню поступивших заказов
Трудозатраты: 1
Описание:
- Процедура автоматически печатает и переводит заказы в статус "В работе"
- Отбирает заказы в статусе "Новый" с признаком
Нужна автоматическая печать в работу
- Для каждого такого заказа вызывает стандартную процедуру смены статуса на Выполняется
- Снимает признак
Нужна автоматическая печать в работу
- Отбирает заказы в статусе "Новый" с признаком
- Процедура будет запускаться как задание планировщика
Передача меню на сервер веб-приложения
Трудозатраты: 3
Описание:
- Процедура подготавливает меню в формате JSON и передает на сервер веб-приложения
/update_menu
- Для работы процедуры, в торговом зале должен быть прописан
Токен авторизации
- Подготовка меню
- Меню формируется по таблице меню текущего торгового зала
- Иерархия раскладок принудительно приводится к двухуровневой структуре
- Если товар присутствует на нескольких раскладках, то в веб-приложение он будет передан только по первой раскладке
- Учитывается расписание замен на текущий момент (по серверу)
- Отправят запрос на веб-сервер
/update_menu
- Результат запроса не контролируется
- Процедура может запускаться как задание планировщика или вручную из складской части программы
Передача стоп-листа на сервер веб-приложения
Трудозатраты: 2
Описание:
- Задание для планировщика, запускается каждую минуту
- Выполняется проверка, поменялся ли стоп-лист с даты последней передачи стоп-листа на веб-сервер
- Если не поменялся, то ничего не происходит
- Если поменялся, то запускается процедура выгрузки стоп-листа
- Процедура подготавливает стоп-лист текущего ТЗ в формате JSON и передает на сервер веб-приложения
/update_stop-list
- В случае успешной передачи, фиксируется дата последней передачи стоп-лист на веб-сервер
- Процедура подготавливает стоп-лист текущего ТЗ в формате JSON и передает на сервер веб-приложения
Отложенное считывание кодов маркировки (Честный знак)
Трудозатраты: 8
Описание:
- Изменить структуру хранения кодов маркировки (КМ), чтобы для одной строки можно было задать несколько КМ
- Реализовать МЕМЕ-структуру по аналогии с алкоголем
- Разрешить сворачивание строк с КМ
- Добавление новых АМ в МЕМО-структуру сворачиваемой строки
- Сворачивание как отдельная функция и сворачивание при добавлении
- Учесть добавление через прямой ввод КМ и отдельный ввод КМ после добавления
- Разделение строк с КМ
- Разделять МЕМО-структуру при разделении строки
- Добавить интерфейс управления КМ (просмотр, удаление, добавлением КМ в строки заказа)
- Добавить инструмент контроля наличия КМ
- По аналогии с алкоголем будет появляться кнопка "Маркировка", если в заказе есть товары без маркировки
- Добавить запрет на печать чека по заказу, где есть товары без маркировки
Верификация клиента (/jup/client
)
Трудозатраты: 1
Метод: GET
. Параметры:
-
client_id
- Обязательный. Идентификатор клиента
Описание:
- Дешифрует
client_id
, получает UID клиента - Выполняет поиск клиента в базе по UID
- Если клиент не найден, то возвращает ошибку
- Если клиент найден, то возвращает успех
Ответ успех:
{
"result": "success"
}
Ответ ошибка:
{
"result": "error",
"desc": "Клиент не найден"
}
Создание запроса на авторизацию клиента (/jup/client_start_check
)
Трудозатраты: 3
Описание:
- По
session_id
находитЗапрос на авторизацию клиента
- Если такой запрос есть, и он был в течении последних 5 минут, то возвращает ошибку. Чтобы нельзя было отправлять SMS чаще чем 1 раз в 5 минут
- Текст ошибки: "Повторный запрос кода возможен через [n] мин."
- По переданному номеру телефона находит клиента в базе
- Если данные не найдены, возвращает ошибку. Авторизоваться могут только те клиенты, которые есть в базе Юпитера
- Текст ошибки: "Номер телефона не найден в системе"
- Формирует проверочный код, который состоит из пяти цифр, и отправляет его по SMS на номер телефона клиента (через сервис https://stream-telecom.ru/)
- Создает объект
Запрос на авторизацию клиента
, в объекте фиксируется- Клиент
- Проверочный код
-
session_id
с которого был создан запрос - Дата\время создания запроса (по серверу)
- Кол-во проверок. Начальное значение 0
- Возвращает успешный ответ
Метод: POST
. Тело запроса:
{
"phone": "79998886655", // Введенный номер телефона. Обязательный
"session_id": "5595236c62914db69d5c07e064530700" // Идентификатор сессии. Обязательный
}
Ответ успех:
{
"result": "success"
}
Ответ ошибка:
{
"result": "error",
"desc": "Повторный запрос кода возможен через 2 мин."
}
Авторизация клиента по проверочному коду (/jup/client_check
)
Трудозатраты: 1
Описание:
- Сервер ресторана по
session_id
находитЗапрос на авторизацию клиента
- Если
Запрос на авторизацию клиента
не найден, то возвращает ошибку- Текст ошибки "Проверочный код не найден, запросите новый код"
- Если
Запрос на авторизацию клиента
был создан более чем 3 минуты назад, то возвращает ошибку и удаляетЗапрос на авторизацию клиента
- Текст ошибки: "Проверочный код устарел, запросите новый код"
- Нужно, чтобы пользователь не мог использовать старый код
- Если кол-во проверок в
Запросе на авторизацию клиента
>= 3, то возвращает ошибку и удаляетЗапрос на авторизацию клиента
- Текст ошибки: "Введен неверный проверочный код. Осталось попыток 0. Запросите новый код"
- Сверяет сверяет
code
с кодом изЗапроса на авторизацию клиента
- Если коды не совпадают, то возвращает ошибку и увеличивает кол-во проверок на 1
- Текст ошибки: "Введен неверный проверочный код. Осталось попыток: [n]"
- Если коды совпадают то возвращает успешный ответ
Метод: POST
. Тело запроса:
{
"code": "12345", // Введенный проверочный код
"session_id": "5595236c62914db69d5c07e064530700" // Идентификатор сессии. Обязательный
}
Ответ успех:
{
"result": "success",
"client_id": "00000000-0000-0000-9001-000000000805"
}
Ответ ошибка:
{
"result": "error",
"desc": "Введен неверный проверочный код. Осталось попыток: 1"
}
Создание предзаказа (/jup/preorder
)
Трудозатраты: 24
Описание:
- Проверяет все товары из заказа на стоп-лист
- Если один или несколько товаров в стопе, то возвращает ошибку
- Текст ошибки "Товары SSS, SSS, SSS в данный момент не доступны для заказа"
- Если один или несколько товаров в стопе, то возвращает ошибку
- Проверят все товары по механизму оставшегося кол-ва
- Если один или несколько товаров превышают "Оставшееся кол-во", то возвращает ошибку
- Текст ошибки "Товары SSS, SSS, SSS в данный момент не доступны для заказа"
- Если один или несколько товаров превышают "Оставшееся кол-во", то возвращает ошибку
- Формирует предварительный заказ
- На кассе в Юпитере его не видят
- Просмотреть предзаказы можно только через бэкенд Юпитера
- Вручную корректировать предзаказы нельзя
- Перевести предзаказа в заказ вручную нельзя
- Предварительный заказ не влияет на "Оставшееся кол-во"
- Цены для формирования заказа определяются по аналогичному алгоритму из кассы
- Цена с кнопки
- Прейскурант для клиента
- Прейскуранта для торгового зала ТЗ
- Цена из таблицы раскладок
- Применяет все возможные скидки к предзаказу
- Все автоматические скидки
- Настройка "Когда применять автоматическую скидку" игнорируется
- Если используются скидки по расписанию, то "Способ определения скидки" должен быть всегда "Время открытия заказа"
- Скидки клиента. Если клиент определен
- Подарочные товары не применяются
- Все автоматические скидки
- Создает платеж в ЮKassa
- Если создать платеж не получилось, то возвращает ошибку
- Текст ошибки: "Не удалось создать платеж в ЮKassa"
- ID платежа сохраняется в предзаказе
- Возвращает успешный ответ
Метод: POST
. Тело запроса:
{
"date": "2024-04-08 15:21:03", // Дата\время оформления заказа
"client_id": "00000000-0000-0000-9001-000000000805", // Идентификатор клиента
"cart": { // Содержимое заказа
"items": [ // Товарная часть
{
"id": "T20231", // Идентификатор товара
"count": 1 // Количество
},
{
"id": "555333111",
"count": 3,
"modifiers": [ // Массив вложенных модификаторов к этому товару
{
"id": "6021", // Идентификатор товара
"count": 1 // Количество
},
{
"id": "6042",
"count": 1
}
]
}
]
}
}
Ответ успех:
{
"result": "success",
"pretotal": 5000.00,
"discount": 100.00,
"total": 4900.00,
"confirmation_url": "https://yoomoney.ru/api-pages/v2/payment-confirm/epl?orderId=23d93cac-000f-5000-8000-126628f15141"
}
Ответ ошибка:
{
"result": "error",
"desc": "Что-то пошло не так"
}
Изменение статуса оплаты (/jup/payment
)
Трудозатраты: 4
Описание:
- Находит предзаказа по
ID платежа
- Изменяет статус платежа
- Когда статус платежа становится
succeeded
(подробнее о статусах в ЮKassa), Юпитер изменяет тип с Предзаказа на Заказ- Заказ появляется на кассе в статусе Новый
- Изменяется "Оставшееся кол-во"
- В заказ проставляется признак
Нужна автоматическая печать в работу
- Отправляется SMS на номер телефона клиента с текстом: "Оформлен заказ № NN-NN-NN на сумму NNNN руб., сидка NN руб."
- SMS отправляется через сервис https://stream-telecom.ru/
- Результат отправки SMS не контролируется
Метод: POST
. Тело запроса: https://yookassa.ru/developers/using-api/webhooks#using
Ответ успех:
{
"result": "success"
}
Ответ ошибка:
{
"result": "error",
"desc": "Платеж не найден"
}
Система JUPITER www.jupiter.systems (с) 2024г.
Нет комментариев