Документация
Архитектура системы
Используемые технологии
Php7.1
MariaDb
RabbitMQ + supervisord
Yii1 \ Yii2
Интеграция с поставщиками
Push - интеграция при помощи REST API zelenka. В этом случае поставщик реализует взаимодействие на своей стороне
Pull - в этом случае интеграция реализуется на стороне zelenka
Данные обмена
География
Точки продаж
Номенклатура
Остатки по каждой точки продаж
Создание заказа
Получение статусов заказа
Отмена заказа
Документация: https://zelenka.ru/page/api_docs
Технические замечания
RabbitMQ используется при обновлении цен и остатков для обеспечения равномерной нагрузки
Скорость обработки данных определяется оптимизацией алгоритма, оптимизацией работы с БД и количеством обработчиков
Отдельное требование по обновлению остатков: интервал обновления 20 минут
Средства разработки, платформы, СУБД:
PHP 7.1, Yii 1/2, MySQL
MariaDb
HTML5
javaScript (jQuery, Bootstrap)
Git workflow
RabbitMQ + supervisord
мобильная разработка (android, ios, hybrid)
Год внедрения в промышленную эксплуатацию 2019
Собственная разработка ООО "ВиртуалСервис"
Документация для подключения к сервису https://zelenka.ru/page/api_docs
В системе реализован программный интерфейс для получения и добавления данных о Заказах. Данные выгружаются по http протоколу. Формат на выбор - xml или json.
Используемые статусы
200 OK — это ответ на успешные GET, PUT, PATCH или DELETE. Этот код также используется для POST, который не приводит к созданию.
201 Created — этот код состояния является ответом на POST, который приводит к созданию.
204 Нет содержимого. Это ответ на успешный запрос, который не будет возвращать тело (например, запрос DELETE)
400 Bad Request — этот код состояния указывает, что запрос искажен, например, если тело не может быть проанализировано либо ошибка в параметрах запроса.
401 Unauthorized — Если не указаны или недействительны данные аутентификации.
404 Not found — если запрашивается несуществующий ресурс
Отличия в работе тестового и рабочего серверов
Тестовый сервер возвращает ответы описанные в документации. Используя эти ответы можно понять что происходит, успешно ли обработан запрос и т.п.
Рабочий сервер возвращает пустой ответ с кодом 200, т.к. все данные он сразу передает серверу обработки очередей. Обработка производится в отложенном режиме, результаты могут быть присланы по почте, если это включено в настройках.
Адрес тестового окружения - http://api.prot.zelenka.ru
1. Аутентификация
Аутентификация основана на протоколе OAuth 2.0.
Предварительным запросом получается access_token. Который необходимо потом передавать как BearerToken в заголовке последующих запросов.
Например, первичный запрос токена:
Производится по адресу https://api.zelenka.ru/auth/login методом POST
POST api.zelenka.ru/auth/login
Content-Type: application/json
{
"username": "user123",
"apikey": "key123"
}
Ответ:
{
"access_token": "6755a48baaf6ee374f4ef55e07bbd2a9",
"token_type": "bearer",
"expires_in": 86400,
"refresh_token": "99afa0362e5c579ecaf4e2621bf1ef69"
}
В последующих запросах выданный access_token необходимо передавать в заголовке как BearerToken.
Срок жизни выданного токена составляет 86400 секунд - значение поля expires_in.
После истечения срока действия access_token, его нужно обновить. Обновление производится с помощью refresh_token, срок действия которого 1 месяц.
POST api.zelenka.ru/auth/refresh
Content-Type: application/json
{
"refresh_token": "a36763c8e8473004841ed9f691166de4"
}
Ответ:
{
"access_token": "ab475c1471c2d6342f2f620d6fb59838",
"token_type": "bearer",
"expires_in": 86400
}
При использовании устаревшего refresh_token будет выдана ошибка 401 Refresh token not found or expired.
2. Item - Товары
При пакетной загрузке производится создание нового прайслиста контрагента, который используется в дальнейших расчетах цен.
При одиночном обновлении производится корректировка значения последнего имеющегося прайслиста контрагента.
Пакетная загрузка цен
Данные для добавления передаются в теле POST запроса в формате JSON.
Регион необходимо указывать параметром location_id.
Пример запроса:
POST /item/batch-update?location_id=1
HTTP/1.1
HOST: api.zelenka.ru
[
{"id": "ЦБ-001123311", "name": "Azitrol 50ml", "price": "82.11", "price_min": "78.1", "manufacturer_name": "ПерваяФабрика", "barcode": "5646233"},
{"id": "ЦБ-001123314", "name": "Azitrol 50ml", "price": "85.11", "price_min": "78.4", "manufacturer_name": "ПерваяФабрика", "barcode": "56462333"},
{"id": "ЦБ-001123315", "name": "Azitrol 50ml", "price": "", "price_min": "78.5", "manufacturer_name": "ПерваяФабрика", "barcode": "56462334"}
]
Ответ сервера
{
"success": 5,
"errors": []
}
В ответе содержится количество успешно добавленных позиций, и массив ошибок если они есть.
Пример запроса на одиночное обновление данных
POST /item/update
HTTP/1.1
HOST: api.zelenka.ru
{
id: 21,
name: "Азитрол капс.50мг",
barcode: 23426546,
price: 224.12,
price_min: 220.00
}
Параметры запроса
id - код товара
name - название товара
manufacturer_name Название производителя
barcode - ш/код производителя через запятую
price – цена продажи для сайта
price_min - минимальная цена продажи
Ответ сервера
При успешном добавлении ответ возвращается с кодом статуса 201.
{
"id": "21",
"name": "Азитрол капс.50мг",
"manufacturer_name": "",
"barcode": "23426546",
"price": "224.12",
"price_min": "220.00"
}
3. Warehouse - Точки продаж
Пример запроса на добавление данных
POST /warehouse/update
HTTP/1.1
HOST: api.zelenka.ru
{
"id": "341",
"name": "Аптека1",
"brand": "Бренд1",
"location_id": 78,
"address": "г. Санкт-Петербург, ул.Маршала Казакова, д.11",
"phone": "8 (812) 000-11-22",
"worktime": "Пн-Пт 8:00-20:00; Сб-Вс 10:00-18:00",
"notify_order_email": "email_for_notify@your_domain.ru",
"flag24hours": 1,
"organisation": {
"inn": "123456",
"name": "ООО Здоровья всем"
},
"on_request": 0,
"is_deleted": 0
}
Параметры запроса
id - идентификатор. При запросе производится проверка есть ли уже точка у этого контрагента с данным идентификатором, если нет то создается, если есть то данные обновляются.
name - название точки продаж (должно быть уникально для контрагента)
brand - бренд, торговое название аптечной сети/аптеки (название на вывеске)
location_id - обязательный параметр - код города/региона (78 - Санкт-Петербург)
address - адрес точки продаж
phone - телефон точки продаж
worktime - время работы. Если время работы имеет много вариантов, то предпочтителен следующий формат:
"Пн-Пт 8:00-20:00; Сб 10:00-18:00; Вс 12:00-18:00". В местах с ограниченной шириной будет производиться перенос по знаку ";" точка с запятой.
notify_order_email - email для уведомлений, если заполнен то будут приходить письма-уведомления о заказах. Можно указать несколько email, разделите запятая или точка с запятой. Например email_for_notify@your_domain.ru; second_notify@your_domain.ru.
flag24hours - признак круглосуточной работы.
organisation - информация о юридическом лице. Для объекта organisation поля inn и name обязательны. Необязательно для заполнения.
on_request - точка продаж работает под запрос с главного склада. Значение 1 = точка «под заказ» со склада включена, Значение 0 = точка «под заказ» со склада выключена.
is_deleted - флаг обозначающий что данная точка выключена для отображения на сайте. Значение = 1 точка выключена, по умолчанию или значение = 0 точка включена
Обязательные поля
id
location_id
Ответ сервера
При успешном добавлении ответ возвращается с кодом статуса 201, при обновлении 200.
В случае если передается точка продаж с флагом is_deleted и на стороне Зеленки ее нет, код ответа будет 208 Already Reported. Удаленные точки не создаются, но если точка существует, устанавливается флаг удаления.
В теле ответа массив параметров точки продаж.
{
"id": 44,
"name": "NewWarehouse",
"location_id": 78,
"address": "Невский, 1",
"phone": "88123121212",
"worktime": "8:00 - 22:00",
"flag24hours": 1,
"organisation": {
"inn": "123456",
"name": "ООО Здоровья всем"
},
"on_request": 0
}
Возможные коды ошибок
409: Duplicate entity with name: {name} (id: {id}) - в случае добавления точки продаж с дубликатом названия.
4. Onhand - Остатки
Пакетное добавление/обновление информации по остаткам
Пример запроса
POST /onhand/batch-update
HTTP/1.1
HOST: api.zelenka.ru
[
{"id": "ЦБ-00004897", "warehouse_id": 341, "quantity": 8.1},
{"id": "ЦБ-00004898", "warehouse_id": 341, "quantity": 12},
{"id": "ЦБ-00004899", "warehouse_id": 3411, "quantity": 0.00}
]
Параметры запроса
Информация принимается в теле запроса в формате JSON. Ограничение на размер тела запроса 16 мегабайт.
Каждый элемент передаваемого массива должен содержать следующие элементы:
id - идентификатор товара
warehouse_id - идентификатор точки продаж
quantity - количество (приводится к целому)
Ответ сервера
В ответе содержится информация:
success - о количестве успешно обновленных/добавленных записей об остатках
errors - массив с ошибками по неуспешно обновленным записям
{
"success": 2,
"errors": {
"ЦБ-00004899": "Warehouse not found"
}
}
Обработка полных остатков
В соответствии с регламентом, раз в сутки необходимо передавать остатки по всем товарам по точке продаж. Для запроса такого типа необходимо указать GET параметр isfull=1.
Пример запроса
POST /onhand/batch-update?isfull=1
HTTP/1.1
HOST: api.zelenka.ru
[
{"id": "ЦБ-00004897", "warehouse_id": 341, "quantity": 8.1},
{"id": "ЦБ-00004898", "warehouse_id": 341, "quantity": 12},
{"id": "ЦБ-00004899", "warehouse_id": 342, "quantity": 3.00}
{"id": "ЦБ-00004897", "warehouse_id": 342, "quantity": 90.00}
...... остатки по всем товарам точек продаж 341, 342 ......
]
Добавление/обновление информации по одному товару
POST /onhand/update
HTTP/1.1
HOST: api.zelenka.ru
{
"id": 7,
"warehouse_id": 123,
"quantity": 8.1
}
Параметры запроса
Информация принимается в теле запроса в формате JSON.
id - обязательный параметр - идентификатор товара.
warehouse_id - идентификатор точки продаж
quantity - количество (приводится к целому)
Ответ сервера
При успешном добавлении ответ возвращается с кодом статуса 201, при обновлении 200.
В теле ответа переданные параметры и количество которое было принято.
{
"id": 44,
"warehouse_id": "341",
"quantity": 8
}
5. Order - Заказы
Статусы заказов
1 - Новый
2 - Собран, готов к выдаче
3 - Получен, выдан
4 - Завершен
5 - Отменен
7 - Принят в работу
9 - Ожидает отмены (отмена инициирована клиентом)
10 - Отменён клиентом
Статус оплаты заказа
0 - не оплачен
1 - оплачен
Обновление заказа:
Пример запроса на обновление данных:
POST /order/update
HTTP/1.1
HOST: api.zelenka.ru
{
"id": 123,
"status": 2,
"is_paid": 1,
"guid": "12345",
"items": [
{
"id": "ЦБ-00031525",
"quantity": 2,
"price": 120
},
{
"id": "ЦБ-00031524",
"quantity": 1,
"price": 252
}
],
"fiscal_datetime": "18.01.01 12:00",
"fiscal_number": "123123",
"fiscal_doc": "123123",
"fiscal_attribute": "12341234"
}
Параметры:
id (обязателен) - идентификатор заказа;
status - статуст заказа;
is_paid - признак того что заказ оплачен;
guid - номер заказа в системе контрагента
items - элементы заказа:
item_id - идентификатор товара;
quantity - количество товара;
price - цена продажи;
Дополнительно для заказов статуса 4 –выполнен:
fiscal_datetime – дата и время чека по ККТ в формате ГГ.ММ.ДД ЧЧ:ММ
fiscal_number – номер фискального накопителя (16-значное число)
fiscal_doc – номер фискального документа (10-значное число)
fiscal_attribute – фискальный признак документа (10-значное число)
Пример ответа с сервера:
{
"id": 123,
"status": 2,
"is_paid": 1
}
При попытке сменить статус на недопустимый будет возвращена ошибка.
Получение информации о последних заказах
Пример запроса:
POST /order/list
HTTP/1.1
HOST: api.zelenka.ru
{
"check_from": "2018-12-01 10:11:12",
“check_by”: “created”,
"warehouse_id": 555
}
Параметры запроса:
check_from (обязательный) - дата и время последнего успешного получения заказов.
check_by - определяет чем является check_from датой создания или датой обновления заказа. Принимает два значения: created (по-умолчанию), updated
warehouse_id - код точки продаж, если не указан, то по всем точкам.
fields - дополнительная информация по заказу и элементам заказа. В настоящий момент может принимать значение: barcodes
Пример ответа:
{
"check": "2018-12-04 12:41:20",
"check_by": "created",
"orders": [
{
"id": 451,
"user_name": "Тест",
"user_phone": "79219613944",
"warehouse_id": "555",
"created_at": "2018-11-27 15:52:20",
"status": 1,
"is_paid": 0,
"promocode": null,
"items": [
{
"id": 456456,
"quantity": "2.000",
"price": "1062.00",
"amount": "2124.00"
}
]
}
]
}
Ответ содержит:
check - метка времени, на какой момент произведена выгрузка заказов. Рекомендуется её сохранять и использовать при следующем запросе.
check_by - с каким значением использовалось поле check. См. описание запроса выше.
orders - массив заказов
id - идентификатор заказа
user_name - ФИО клиента
user_phone - телефон клиента
warehouse_id - код точки продаж
created_at - дата создания заказа
status - статус заказа (коды статусов указаны в начале)
is_paid - признак оплаты заказа
promocode - промокод, если он был применён
items - элементы заказа
id - идентификатор товара
name - название товара, выводится при отсутствии сопоставления
barcodes - штрихкоды товара, выводятся при отсутствии сопоставления
manufacturer - производитель, выводится при отсутствии сопоставления
quantity - количество
price - цена
amount - сумма
Ответ содержит максимум 100 заказов.
Обработка отмены заказа пользователем
1. При получении списка заказов отобрать заказы со статусом 9 (отмена инициирована пользователем)
2. Отменить заказ у себя в системе
3. Прислать изменения по статусу заказа (статус 10). Запрос Обновление заказа.
Договор
Шаблон договора находится здесь
Базовая комиссия составляет 6% от суммы выкупленных заказов.
Все скидки, которые транслируются покупателям со стороны платформы компенсируются по итогам расчетного периода.