====== Описание протокола взаимодействия с APIv2 мини-доставки ====== **ВНИМАНИЕ** Вторая версия API поддержана в DeliveryHatch не ниже **v3.0.5.959**\\ Общий смысл запросов и ответов остался неизменным, однако их содержимое переработано с целью обеспечить \\ более качественную работу внешних систем за счет снижения влияния человеческого фактора. APIv2 мини-доставки позволяет: * Получить актуальное состояние меню из ресторана втч с учетом текущих ограничений блюд и стоп-листа на кассе.\\ * Предварительно проверить сформированную во внешней системе корзину гостя на предмет ошибок на стороне rk7. * Передать заказ гостя на кассу rk7 посредством мини-доставки. \\ Поддержана передача оплаты и персональной скидки для гостя. * Проверить текущее состояние ранее сформированного заказа. ===== Общие положения ===== API доставки реализовано в рамках HTTP протокола.\\ Каждый запрос к API должен иметь заголовок Token, значение которого выдается владельцем доставки. Токен передается без префикса: //Token: *token*// Базовый URL для запросов: **http://IP:PORT/api/v2/ext/** Этот URL можно использовать для проверки работоспособности. Если набрать в любом браузере: http://192.168.1.10:11011/api/v2/ext/ - при работоспособном настроенном API мы должны получить ответ result false msg "\"Token\" header expected." В данном примере 11011 - порт DeliveryHatch, 192.168.1.10 - IP компьютера с установленным сервером мини-доставки. Аналогично стоит проверять доступность сервиса извне после проброса порта. **Важно** Не передавайте "нейтральные" значения для необязательных полей в запросах, если нет вещественных данных для этих полей. Необязательные поля могут быть безболезненно исключены из запроса. ===== Список доступных функций ===== [[external:доставка:api:extv2#проверка_соединения|/ping]] - проверка соединения [[external:доставка:api:extv2#получение_меню|/getmenu]] - получение меню [[external:доставка:api:extv2#валидация_корзины|/validate]] - проверка возможности создания заказа [[external:доставка:api:extv2#создание_заказа|/postorder]] - создание заказ [[external:доставка:api:extv2#получение_статуса_заказа|/orderstate]] - Получение статуса заказа [[external:доставка:api:extv2#получение_списка_активных_заказов|/expressorders]] - Получение списка заказов ===== Проверка соединения ===== Для проверки работоспособности цепочки связей ПО, необходимого для формирования заказа, используется запрос **GET /ping** Запрос не ожидает никаких входных параметров. Ответ на запрос содержит JSON объект, представленный полем **result: boolean** - индикатор успешного выполнения запроса, полем **msg: string**, в котором будет передан текст ошибки в случае, если **result = false**, иначе вложенным объектом data, содержащим поля **DHVersion** - Текущая версия модуля мини-доставки, **CSVersion** - текущая версия кассового сервера r-keeper и поле **CSNetName** - сетевое имя кассового сервера, с которым работает модуль мини-доставки. Начиная с DHVersion: "3.0.6.1222" в ответе будет передаваться объект "params", содержащий локальные для DeliveryHatch данные для интеграции с сервисом dadata, а так же режим работы ресторана (/domains/delivery/const/const.py) Пример успешного ответа:\\ { "result": true, "data": { "DHVersion": "3.0.6.1222", "CSVersion": "7.6.0.81", "CSNetName": "CONF_MIDSERVER", "params": { "dadata_apikey": "52b77b6f5ce32e0ab2af8d30eafdb2cc18961cef", "dadata_basecity": "Новосибирск", "dlvfrom": "9,00", "dlvto": "20,00", "dlvperiod": "15" } } } **params.dadata_apikey** - Ключ для доступа к сервису dadata\\ **params.dadata_basecity** - Базовый город для подстановки адресов\\ **params.dlvfrom** - Доставка начинает работать "С" ЧЧ,MM\\ **params.dlvto** - Доставка работает "ДО" ЧЧ,MM\\ **params.dlvperiod** - Шаг времени в минутах, на которое можно оформить заказ \\ **ВНИМАНИЕ!!!** Если в ответ на данный запрос вы получили **result = false**, то все дальнейшие попытки воспользоваться API доставки бессмысленны в виду наличия проблем на стороне ресторана.\\ Однако и положительный ответ на данный запрос не гарантирует отсутствия ошибок в дальнейшем, т.к. проверяет только отсутствие проблем на физическом уровне. Логические ошибки должны быть так же обработаны внешней системой. ===== Получение меню ===== Для получения списка блюд, доступных к заказу необходимо отправить **GET запрос /getmenu** В ответ вернется JSON объект, содержащий поля result:boolean, msg:string или data:array\\ result - указывает на существование ошибки при обработке запроса. (result = false - запрос не выполнен)\\ msg - текстовое сообщение. В случае ошибки (result = false) будет передан текст ошибки\\ data - один, или несколько JSON объектов, описывающих блюда, доступные к продаже\\ Пример объекта, описывающего блюдо:\\ { "code": 55, "name": "Булочка с корицей", "categpath": "Кухня\\Выпечка", "categcode" : 88, "recipe": "Сдобная булочка в посыпке из сахарной пудры и корицы.", "price": 6500, "ishit":0, "rests": 5, "modifiers": [ { "schemeid": 1001058, "groupid": 1001060, "groupname": "Тестовая группа 2", "uplimit": 2, "downlimit": 1, "freecount": 0, "changesprice": true, "items": [ { "ident": 1001063, "code": 31, "name": "Модификатор 2 1", "limit": 1, "price": 1000 }, { "ident": 1001064, "code": 39, "name": "Модификатор 2 2", "limit": 1, "price": 0 } ] } ] } **code** - Код блюда в справочнике системы. Должен быть передан при создании заказа.\\ **name** - Название блюда для отображения.\\ **categpath** - Расположение блюда в дереве меню в справочниках r-keeper. Служит для разделения блюд по категориям\\ **categcode** - Код категории меню из r_keeper, к которому пренадлежит блюдо.\\ **recipe** - Значение поля "Рецепт" для блюда в справочниках rk-keeper. Может содержать данные БЖУ, рецепт или простое описание блюда, которое будет доступно в интерфейсе доставки.\\ **price** - Стоимость одной порции блюда в копейках.\\ **ishit** - Флаг - является ли блюдо популярным. (Для отображения в отдельной категории - "ХИТ")\\ **rests** - Информация об остатках блюда в ресторане.\\ Если **rests > 0**, то добавить в заказ можно не более **rests** порций блюда.\\ Если **rests = -1**, то ограничений на количество доступных порций со стороны ресторана не передано.\\ Если блюдо по какой либо причине не может быть продано на кассе ресторана, то оно попросту не попадет в ответ на запрос. **modifiers** - Список групп модификаторов, доступных для блюда:\\ **modifiers[n]:**\\ **schemeid** - Идентификатор схемы модификаторов\\ **groupid** - Идентификатор группы модификаторов\\ **groupname** - Название группы модификаторов\\ **uplimit** - Максимальное кол-во модификаторов, которое можно выбрать из этой группы (-1 - нет ограничений)\\ **downlimit** - Минимальное кол-во модификаторов, которое можно выбрать из этой группы (-1 - нет ограничений)\\ **changesprice** - Изменяет ли модификатор цену. Если false, то стоимость модификатора не нужно прибавлять к стоимости блюда\\ **freecount** - Кол-во бесплатных. Если кол-во модификаторов <= freecount, то их стоимость 0, далее по price.\\ **items** - Список модификаторов в группе.\\ **items[n]:**\\ **ident** - Идентификатор модификатора\\ **code** - Код модификатора\\ **name** - Название модификатора\\ **limit** - Максимальное кол-во данного модификатора для одного блюда\\ **price** - стоимость одной порции модификатора\\ ===== Валидация корзины ===== Для проверки возможности добавления в заказ содержимого корзины гостя предусмотрен запрос **POST /validate** В теле POST запроса ожидается JSON объект, частично описывающий заказ гостя: { "table": 1, "type": 1, "discount": 3, "content": [ { "code": 61, "quantity": 1, "modifiers": [ { "code": 31, "count": 1 } ] } ] } **(**так отмечены НЕ обязательные поля**)** **(table)** - (int) Код стола из r_keeper. Если передан, то будет использован при создании заказа на кассе. Если не передан, то будет использован код стола из конфигурации мини-доставки. **(type)** - (int) Тип заказа. 0 - Самовывоз, 1 - доставка.\\ **(discount)** - (int) Код скидки из справочников rk7, с учетом которой будет рассчитана сумма заказа.\\ **content** - (array) Массив блюд, составляющих корзину гостя. (Не может быть пустым)\\ **content[n].code** - (int) Код блюда из справочников r-keeper, полученный в запросе /getmenu\\ **content[n].quantity** - (int) Количество порций блюда.\\ **(content[n].modifiers)** - (array) Список модификаторов, добавляемых к блюду.\\ **modifiers[n].code** - (int) - Код модификатора\\ **modifiers[n].count** - (int) - Кол-во модификаторов на порцию блюда\\ Результат выполнения запроса передастся в поле JSON объекта result, и в случае result = false будет передано поле msg, содержащее текст ошибки.\\ В случае result = true в поле **order** будет передана информация о заказе, каким его видит r-keeper: "order": { "amount": 20700, "discountsum": 2300, "items": [ { "code": 61, "name": "Кебаб из курицы", "price": 22000, "quantity": 1, "discounted": 1300, "total": 20700, "modifiers": [ { "code": 31, "name": "Модификатор 2 1", "count": 1 } ] } ], "discounts": [ { "code": 3, "name": "11", "total": 2300 } ] } **amount** - Сумма заказа, рассчитанная r-keeper (с учетом возможной скидки)\\ **discountsum** - Общая сумма скидки по всему заказу\\ **items** - Список блюд, которые будут добавлены в заказ.\\ **items[n].discounted** - Общая сумма скидки по данному блюду (с учетом количества)\\ **items[n].total** - Окончательная сумма по блюду (с учетом количества и суммы)\\ **items[n].modifiers** - Информация о модификаторах, привязанных к блюду\\ **discounts** - Список скидок, которые будут добавлены в заказ.\\ **discounts[n].code** - Код скидки, применной к заказу\\ **discounts[n].name** - Имя скидки \\ **discounts[n].total** - Общая сумма скидки\\ На основе ответа на данный запрос внешняя система должна скорректировать корзину гостя, пересчитать суммы по блюдам с учетом скидок, дабы показать актуальную информацию об окончательной сумме заказа.\\ Не стоит пренебрегать этим запросом если Вы не планируете передавать скидку гостя в заказ, ведь в ресторане может быть настроена автоматическая скидка. ===== Создание заказа ===== Для создания заказа необходимо отправить POST запрос **/postorder**, в теле которого должен содержаться JSON объект следующего содержания:\\ { "guest": { "sname": "Иванов", "fname": "Иван", "mname": "Иванович", "cardcode":"1000", "meta": {}, "phone": "+7 (963) 949-99-99 ", "address": "Ул.Федосеева", "longitude":85.131548, "latitude":55.164833 }, "order":{ "table" : 2, "type": 1, "comment": "Две персоны", "status_callback": "https://yoururl.com/yourmethod", "discount": 3, "paid":6000, "deliverat": "2020-04-08 22:30:00", "content": [ { "name": "Кебаб из курицы", "code": 55, "quantity": 1, "modifiers":[ { "code": 31, "name": "Модификатор 2 1", "count": 1 } ] } ] } } **(**Так отмечены необязательные поля**)** **guest.[s,(f,m)]name** - (str) Фамилия, Имя и Отчество гостя соответственно.\\ **guest.phone** - (str) Номер телефона гостя. **Все спецсимволы будут удалены**\\ **guest.address** - (str) Адрес доставки (необязателен при order.type = 0)\\ **(guest.longitude), (guest.latitude)** - (float) - Долгота и широта адреса доставки. *не передавайте **null**\\ **введено с версии 3.0.5.983**\\ **(guest.meta)** - (Object) Метаданные о пользователе. JSON объект любого содержания.\\ Не используется в логике ПО, но возвращается в orderstate, expressorders и order.status_callback **введено с версии 3.0.5.1053**\\ **(guest.cardcode)** - (str) Код карты системы лояльности (например ПДС) (**НЕ РЕКОМЕНДУЕТСЯ К ИСПОЛЬЗОВАНИЮ**)\\ **введено с версии 3.0.5.1053**\\ **order.table** - (int) Код стола из r_keeper. Если передан, то будет использован при создании заказа на кассе. Иначе будет использован тот, что указан в конфигурации мини-доставки. **order.type** - (int) Тип заказа. 0 - Самовывоз, 1 - Доставка.\\ **(order.comment)** - (str) Комментарий к заказу\\ **(order.discount)** - (int) Код скидки из справочника r-keeper, которая должна быть добавлена в заказ.\\ **(order.paid)** - (int) Сумма произведенной гостем оплаты в копейках. Если оплаты нет, то не передавать данное поле\\ **order.deliverat** - (str) Время, к которому гость будет ждать доставку в формате **yyyy-mm-dd hh:mm:ss**\\ Запас по времени должен обсуждаться с конкретным заведением.\\ **(order.status_callback)** - (url string) URL адрес, на который будут отправлены уведомления об изменении статуса заказа.\\ **ВНИМАНИЕ. Внутри доставки адрес приводится к нижнему регистру (HttP://Ya.Ru/Status -> http://ya.ru/status)**\\ При изменении статуса заказа на указанный URL будет отправлен POST запрос со следующим JSON содержимым: { "order_id": Integer, // Идентификатор заказа "guestmeta": Object, // Метаданные гостя "phone_number": String, // Номер телефона гостя "status": Integer //Новый статус заказа } **введено с версии 3.0.5.1053**\\ **order.content** - (array) Список блюд, заказанных гостем. **order.content[n].name, code** - (str, int) Название и код блюда, которые были получены в запросе /getmenu\\ **order.content[n].quantity** - (int) Целочисленное количество порций блюда.\\ **order.content[n].modifiers** - (array) Целочисленное количество порций блюда.\\ **order.content[n].modifiers.name, code** - (str, int) Название и код модификатора.\\ **order.content[n].modifiers.count** - (int) Кол-во модификатора на порцию блюда.\\ В ответ на запрос вернется JSON объект, содержащий поле result:boolean\\ Если result = true, то заказ создан и так же передано поле order_id:int - идентификатор нового заказа\\ Eсли result = false, то при создании заказа возникла ошибка, текст которой будет передан в поле msg:str\\ ===== Получение статуса заказа ===== После успешного сохранения заказа можно получить его статус:\\ GET /orderstate?order_id=**[order_id]** *order_id - ИД созданного заказа, который вернулся в ответ на **/postorder** В ответ на запрос вернется JSON объект, где \\ result:boolean - результат выполнения запроса\\ если result == False, то будет передан msg - текстовое описание ошибки, иначе будет передано поле order, аналогичное таковому из запроса /validate, но дополнительно содержащее следующие поля:\\ **id** - Идентификатор заказа на стороне мини-доставки (равен order_id из запроса)\\ **status** - Текуйщий статус заказа. Расшифровку статусов см ниже.\\ **paid** - Сумма оплат в заказе\\ А так же поле guestmeta, содержащее метаданные о госте, переданные при создании заказа. Пример ответа:\\ { "result": true, "guestmeta": { }, "order": { "id": 5, "status": 10, "amount": 46000, "discountsum": 0, "paid": 46000, "items": [ { "code": 61, "name": "Кебаб из курицы", "price": 22000, "quantity": 2, "discounted": -2000, "total": 46000, "modifiers": [ { "code": 31, "name": "Модификатор 2 1", "count": 1 } ] } ], "discounts": [ ] } } Расшифровка статусов заказов:\\ * 0 - "Ожидает" - Такой статус имеют заказы только что созданные через API \\ Они еще не обработаны оператором в ресторане (в кипере заказа еще нет). \\ Заказы в статусе 0 не возвращают содержимое (массив items) * 1Х - "В работе" - Заказ обработан в заведении и передан на кухню (заказ принят, в кипере создан стол, прошла сервис печать). * 2Х - "В пути" - Заказ отправлен с курьером (в кипере выбит пречек или чек) * 3Х - "В архиве" - Курьер вернулся в ресторан, заказ полностью завершен (ручной статус, никак не связан с кипером) * 4Х - "Отменен" - Работники ресторана отменили заказ по той или иной причине. Переход в этот статус возможен как из статуса 0 (т.е. заказ в кипере не создавался даже), так и из любого другого статуса (т.е. в кипере стол с блюдами был создан, потом все блюда удалены и пустой стол закрыт) ===== Получение списка активных заказов ===== **Введено в версии 3.0.5.983** Позволяет получить список заказов мини-доставки. GET /expressorders Входящих параметров не ожидается В ответ вернется JSON объект, содержащий информацию о текущих принятых (принятых оператором на кассе) заказах доставки\\ { "result": true, "data": [ { "id": 139, "guestmeta": { "EXTID": 122 }, "comment": "БАНК. - ", "dlvdate": "2020-05-04 10:00:00", "status": 10, "sum": 1000, "waiter": "Петров Петр", "address": "ул.Пушкина 7, кв 112", "longitude": null, "latitude": null, "phone": "71234567890", "fullname": "Иванов Иван" } ] } **result** - Результат выполнения запроса. Если **false**, то так же будет передано поле **msg:string** содержащее текстовое описание ошибки.\\ **data** - список открытых в данный момент заказов.\\ Далее для data[n]:\\ **id** - Идентификатор заказа в системе\\ **guestmeta** - Метаданные о госте, переданные при создании заказа.\\ **comment** - Комментарий к заказу\\ **dlvdate** - Дата и время, на которое назначена доставка\\ **status** - Текущий статус заказа в системе (см Получение статуса заказа -> Расшифровка статусов заказов)\\ **sum** - Сумма заказа в копейках\\ **waiter** - Имя пользователя в системе r-keeper, на которого назначен заказ \\ **address** - Адрес доставки\\ **longitude, latitude** - (float) Долгота и широта адреса доставки (может быть null)\\ **phone** - Телефон гостя\\ **fullname** - ФИО гостя\\