done

FTP catalog + REST API


FTP Catalog

Раздел технического описания механизма работы процесса загрузки и синхронизации каталога через протокол FTP, посредством загрузки определенных файлов в директории на ftp сервере. У Ютеки есть ftp сервер, но так же можем использовать сервер партнера.

Технические детали перед началом

Мы можем обрабатывать следующие форматы файлов: CSV (приоритетнее), JSON, XML.

Файлы должны быть в кодировке UTF-8 (промышленный стандарт) или, в крайнем случае, windows-1251.

Если вы рассматриваете формат CSV, просим обратить внимание на его корректное формирование для выгрузок аптек и товаров. А в частности, на формирование строк содержащих спецсимволы: ' " ; ,. Особенно это актуально для наименований товаров, адресов и названий аптек, так как они могут содержать эти символы. Правильные варианты смотри в примерах к файлам.

Аптеки

В корень ftp выгружается файл pharmacies.<формат>, где расширение соответствует формату выгрузки.
Ютека загружает аптеки раз в 3 часа. Партнеру рекомендуется выгружать с такой же периодичностью. Новые файлы выгружаются поверх старых, перезаписывая их.

Поле Обязательное Описание Комментарий
pharmacyId done уникальный идентификатор аптеки По нему будет отправляться заказ в аптеку
title done Название аптеки
region ID Региона аптеки Не обязателен, если аптеки Партнера представлены только в одном регионе
address done Адрес С точностью до дома. Если возможно, без дополнительных комментариев, вида пом.75843б, за магазином канцтоваров
phone done Телефон В международном формате (+71234567890). Если это городской номер телефона, то с кодом города (например для Новосибирска это +7(383)000‒00‒00)
workingHours done Часы работы в формате
location done GPS координаты Latitude,Longitude Например, 59.939032,30.315826. При подстановке в гугл/яндекс/другие карты должна показываться точка на аптеку. По координатам проверяется адрес, если он не точен
email Email аптеки для связи Мы можем присылать email оповещения в аптеку при поступлении новых или отмене заказов

Товары

В корень ftp выгружается файл products.<формат>, где расширение соответствует формату выгрузки.
Ютека загружает товары раз в 3 часа. Партнеру рекомендуется выгружать с такой же периодичностью. Новые файлы выгружаются поверх старых, перезаписывая их.

Поле Обязательное Описание
productId done уникальный идентификатор товара в аптечной сети.
barcode done Штрихкод
title done Название
vendor done Производитель
country done Страна
egk ЕГК код товара, если такой известен
rls RLS код товара, если такой известен
katren Katren код товара, если такой известен

Остатки

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

Остатки выгружаются по-аптечно в директорию /stocks в файлы с именем stocks_<аптека>.<формат>, где суффикс названия соответствует ID аптеки.

Ожидаемые поля в файлах остатков:

Поле Обязательное Описание
productId done ID товара из выгрузки Товаров
pharmacyId done ID аптеки из выгрузки Аптек
price done Цена
quantity done Остаток
partNumber Партия
expirationDate Срок годности в формате ДД.ММ.ГГГГ (например 31.12.2020)

REST API заказов

Этот раздел описывает процесс интеграции Ютеки и Партнера через реализацию на стороне Партнера HTTP REST интерфейса для обработки заказов.

Хоть и реализация интерфейса кладется на плечи Партнера, взаимодействие является двусторонним: Ютека отправляет новые заказы и отмены заказов Партнеру, а Партнер отправляет Ютеке информацию об изменении статуса.

Список используемых методов

Интерфейс Партнёра:

Интерфейс Ютеки:

АПИ и механики работы

В этом разделе описаны технические моменты реализации АПИ и механики работы.

Формат работы АПИ - JSON. HTTP методы, используемые в запросах: POST.

Авторизация

Во время начала интегрирования, Ютека и Партнёр договариваются о способе авторизации и аутентификации друг друга. Это нужно, что бы исключить возможность третьих лиц делать ложные заказы или присылать неправильные статусы. Поэтому Партнёр, при реализации АПИ должен добавить проверку запросов на ключ авторизации.

Пусть, далее в документации, ключ доступа будет hee7vaisahchu4O (случайная строка, не пытайтесь делать с ней запросы).

Ютека может авторизировать запросы способами:

  • Basic Auth авторизация.
    Партнёр закрывает HTTP endpoint при помощи Basic Auth, а Ютека добавляет к запросам логин и пароль доступа.
  • Authorization заголовок.
    Ютека и Партнёр добавляют к своим запросам заголовок с секретным токеном. В HTTP запросе будет заголовок вида Authorization: hee7vaisahchu4O
  • JSON поле в теле запроса.
    Ютека и Партнёр добавляют к телу запроса поле token. Тогда, минимальное тело запроса будет {"token": "hee7vaisahchu4O"}

Работа с ошибками

За успешность выполнения запроса отвечает HTTP Status Code ответа. При успешном выполнении запроса, АПИ должно возвращать код 200 OK.

Если по какой-либо причине запрос выполнился неудачно, АПИ не должно возвращать 200 ОК. В теле отведа должно быть описание ошибки в поле error:

{
    "error": "Ошибка установки соединения с базой данных"
}

А код ответа должен быть одиним из:

  • 403 - Ошибка авторизации, токен или пара логин/пароль не совпали.
  • 400 - В запросе неверные данные. Например, неправильный JSON формат тела запроса.
  • 500 - Остальные ошибки. Недоступность сервера, отказ базы данных и др.

Номера заказов

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

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

Во всех методах (кроме создания заказа) Ютека посылает оба номера utekaOrderId и partnerOrderId и гарантирует, что они соответствуют друг другу.

Поля partnerOrderId и utekaOrderId всегда должны быть JSON String.

Создание заказа

При появлении нового заказа от клиента на сайте Ютеки, делается запрос на подготовленный URL Партнёра в котором будет данные по заказу и контакты клиента.

{
   "utekaOrderId": "123",
   "pharmacyId": "1234",
   "items":[
      {
         "productId": "60001090",
         "quantity": 2,
         "price": 880
      },
      {
         "productId": "60001040",
         "quantity": 1,
         "price": 73000
      }
   ],
   "amount": 74760,
   "name": "Кирилл",
   "phone": "9997651151"
}
Параметр JSON Тип Описание
utekaOrderId String Номер заказа в сервисе Ютеки. (*)
pharmacyId String ID аптеки Партнера
items Array Список позиций заказа. Каждый элемент имеет уникальный productId (т.е. позиции не повторяются)
items.productId String Идентификатор товара Партнёра
items.quantity Number (целочисленный) Количество позиции товара в заказе. Дробные числа не поддерживаются.
items.price Number Цена товара в рублях. Может содержать дробную часть - копейки.
amount Number Общая сумма заказа. Может содержать дробную часть - копейки.
name String Имя/Фамилия/Псевдоним пользователя под которым он будет забирать заказ.
phone String Номер телефона клиента в формате 9001112233 (без +7 или 8)

(*) Используется как ключ идемпотентности.

При успешном получении нового заказа, Партнёр ответить на HTTP запрос статусом 200.

В ответе АПИ должно вернуть оба ID заказа: и Партнера, и Ютеки.

{
  "partnerOrderId": "textAndNumbers12345",
  "utekaOrderId": "99"
}

Это используется для доп. валидации, что заказ принят. Если Партнер, по каким-то причинам, не может присылать свой идентификатор, он может вернуть в partnerOrderId номер заказа Ютеки.

Переотправка заказов (повторные запросы)

Ютека может послать запросы с одним и тем же utekaOrderId. В случае, если на стороне партнера уже есть заказ с этим номером Ютеки, то не нужно создавать новый, а нужно вернуть данные уже созданного заказа.

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

Проверка статуса

Периодически Ютека опрашивает АПИ партнера о текущем статусе заказа. Ютека делает запрос вида:

{
    "orderIds": [
      {"partnerOrderId": "4567", "utekaOrderId": "123"},
      {"partnerOrderId": "xxxx", "utekaOrderId": "4568"},
      {"partnerOrderId": "4569", "utekaOrderId": "2"}
    ]
}

и ожидает в ответ JSON массив из текущих статусов заказов.

[
    {
      "utekaOrderId": "4567",
      "partnerOrderId": "utk-123",
      "status": "cancelled"
     },
    {
      "utekaOrderId": "4568",
      "partnerOrderId": "utk-17",
      "status": "approved"
     },
    {
      "utekaOrderId": "4569",
      "partnerOrderId": "utk-utk",
      "status": "ready"
     }
]

Возможные статусы заказа

  • approved - подтвержден. Новый заказ был обработан системой и/или заказ собирается.
  • ready - готов к выдаче. Заказ укомплектован и клиент может идти забирать его из аптеки.
  • cancelled_by_pharmacy - отменен аптекой. В случае, когда аптека не может выполнить этот заказ. Например, неактуальные остатки или разница в цене в аптеке и в заказе.
  • completed - выполнен. Клиент успешно забрал/выкупил заказ.
  • cancelled - отменен клиентом. Ютека присылает этот статус в методе отмены заказа.

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

graph LR approved[Подтвержден approved] ready[Готов к выдаче ready] cancelled_by_pharmacy[Отменен аптекой cancelled_by_pharmacy] completed[Выполнен completed] cancelled[Отменен клиентом cancelled] endst((Конечный статус)) newOrder((Новый заказ)) clientCancel((Клиент отменяет заказ)) uteka(Ютека) uteka1(Ютека) newOrder-->uteka uteka-->approved approved--Все позиции заказа собраны-->ready approved--Невозможно собрать заказ-->cancelled_by_pharmacy ready--Клиент не забрал заказ-->cancelled_by_pharmacy ready--Клиент выкупил заказ-->completed clientCancel-->uteka1 uteka1-->cancelled cancelled_by_pharmacy-->endst completed-->endst cancelled-->endst style uteka fill:#68e472,stroke:#008012 style uteka1 fill:#68e472,stroke:#008012

Отмена заказа клиентом

Когда клиент отменяет заказ на сайте Ютеки, Партнёру отправляется запрос с телом

{
    "utekaOrderId": "4567",
    "partnerOrderId": "xxx",
    "status": "cancelled"
}

И ожидается ответ с текущим статусом заказа (должен быть cancelled если отмена прошла успешно), как при запросе статуса:

{
    "utekaOrderId": "4567",
    "partnerOrderId": "xxx",
    "status": "cancelled"
}

Обратите внимание, что при отмене заказа Партнёром (в том числе и на стороне аптеки), Партнёр посылает статус cancelled_by_pharmacy, а когда клиент отменяет заказ, то Ютека посылает статус cancelled.

Обновление статуса заказа

URL: https://example.com/srv/ordersrv/api/orders/status

Партнер посылает следующий запрос, когда изменяется статус заказа.

Параметры запроса:

Параметр JSON Тип Обязательное Описание Пример
utekaOrderId String (и содержит целочисленное число) Да Номер заказа в сервисе Ютеки. Передается в запросе создания заказа, в ответе на запрос создания заказа {"utekaOrderId": "333591"}
partnerOrderId String Да Номер заказа в сервисе Партнера. Передается в ответе на запрос создания заказа {"partnerOrderId": "000-5323.ff12"}
status String Да Должен принимать одно из возможных значений. См. Возможные статусы заказа {"status": "ready"}

Примеры: