Ruby-клиент для REST XML API Moysklad
Особенности
- Модуль разработан согласно принципам SOLID. Легко расширяем.
- Все используемые сущности описаны и структурированы. Например Good
- Любые действия с ресурсами (Create, Read, Update, Delete, List).
- Виртуальные действия с ресурсами (
where
,findWhere
) - Автоматическая подгрузка списка если все данные не уместились в один запрос (метод
all
) - Кеширование и предзагрузка ресурса со всеми записями (используем ресурс как локальную базу)
- Работа с нескольмими аккаунтами склада одновременно (отсуствие глобальных переменных).
- Удобная работа с подресурсами (например справочником свойств товара)
-
Ассоциации между сущностями автоматически получают данные по API (
good.features
). - Client для прямого обращения к API в случае крайней необходимости.
Установка
Все, как обычно, добавляем в Gemfile:
gem 'moysklad'
Использование
Создаем благоприятное окружение для работы с API:
universe = Moysklad::Universe.build login:'ВАШ ЛОГИН', password:'ВАШ ПАРОЛЬ'
Список элементов.
Например список товаров (Good
).
universe.goods.list
# => [Moysklad::Entities::Good, Moysklad::Entities::Good, ..]
Обратите внимание, что список возвращается "как есть" и для работы с ним есть более удобные методы.
Параметры списка.
universe.stock.list slotUuid: uuid
Страница товаров:
page = universe.goods.page
# => Moysklad::Entities::Page
page.total
# => 1280
page.count
# => 1000
page.start
# => 0
# page.items
# =>[Moysklad::Entities::Good, ..]
Есть очень удобная возможность автоматически загрузать ВСЕ товары с учетом пейджирования:
> goods = universe.goods.all
> goods.count
> => 1280
> goods
> => [Moysklad::Entities::Page]
Получить конкретный элемент
universe.goods.get $uuid
# => [Moysklad::Entities::Good]
Создаем элемент
Например загрузка заказа покупателя:
co = Moysklad::Entities::CustomerOrder.new
co.vatIncluded = true
co.applicable = true
[...]
co.customerOrderPosition = [Moysklad::Entities::CustomerOrderPosition.new]
created_order = universe.customer_orders.create co
# => [Moysklad::Entities::Good]
created_order.uuid
# => uuid нового заказа
Удаляем элемент
universe.goods.delete $uuid
Кеширование и предзагрузка
Одной из главных возможностей данного модуля является возможность работать с API как с базой данных, не выполняя запрос по получению каждого товара по-отдельности, и выдавать данные их кеша.
Класический способ получить данные по товару делает GET запрос каждый раз:
universe.goods.get $uuid
# => Client: GET exchange/rest/ms/xml/Good/f24937e7-7ba1-11e4-90a2-8ecb000abf12 {}
# => [Moysklad::Entities::Good]
Продвинутый способ вытаскивает все данные сразу и в дальнейшем берет обьекты из кеша:
> universe.goods.find $uuid
# => Client: GET exchange/rest/ms/xml/Good/list {:start=>0}
# => Client: GET exchange/rest/ms/xml/Good/list {:start=>1000}
# => [Moysklad::Entities::Good]
И в следующий раз API уже не дергается:
universe.goods.find $another_uuid
# => [Moysklad::Entities::Good]
Это позволяет экономить на прямых запросах к API и избавляет нас от блокирования моимскладом по ограничению количества запросов за еденицу времени.
Поиск по фильтру
Возвращает список элементов отображенных по фильтру:
universe.features.where goodUuid: uuid
# => [Moysklad::Enities::Feature, Moysklad::Enities::Feature]
Тоже самое, только возвращается первый элемент или nil:
universe.features.findWhere goodUuid: uuid
# => [Moysklad::Enities::Feature]
Список доступных ресурсов:
universe.resources_list
# => [:stock, :embedded_entity_metadata, :custom_entity_metadata, :goods, :good_folders, :uoms, :countries,
:features, :custom_entities, :customer_orders, :warehouses, :companies,
:consignments, :my_companies]
Справочники и подресурсы
Доступ к Мойсклад устроен так, что некоторые справочники запрятаны в одной коллекции. Например если вы хотите получить все виды свойств товаров, то это можно сделать следующим образом.
universe.embedded_entity_metadata.subresource_by_name(:GoodFolder).all
# => [Moysklad::Entities::AttributeMetadata, Moysklad::Entities::AttributeMetadata]
Или получить конкретное свойство:
universe.embedded_entity_metadata.subresource_by_name(:GoodFolder).find uuid
# => Moysklad::Entities::AttributeMetadata
Автоматическая обработка ассоциаций (отношения)
Нравятся belongs_to
и has_many
в рельсах? Тут есть почти тоже самое.
feature = universe.features.find uuid
feature.good
# Client: GET exchange/rest/ms/xml/Good/f24937e7-7ba1-11e4-90a2-8ecb000abf12 {}
# => [Moysklad::Entities::Good]
Пример как получить все данные по товару, включая модификации, свойства и их характеристики:
good = universe.goods.find uuid
# Client: GET exchange/rest/ms/xml/Good/f24937e7-7ba1-11e4-90a2-8ecb000abf12 {}
good.features universe
# Client: GET exchange/rest/ms/xml/Feature/list {}
# => [Moysklad::Entities::Feature, ..]
attribute = good.attributes.first
# => [Moysklad::Entities::Attribute, ..]
attribute.is_dictionary?
# => true
Получаем вид свойства:
attribute.embedded_entity_metadata universe
# Client: GET exchange/rest/ms/xml/Metadata/list {}
# => [Moysklad::Entities::AttributeMetadata]
Получаем описание пользовательского справочника к которому принадлежит свойства
dictionary = attribute.embedded_entity_metadata(universe).dictionatyMetadata(universe)
# Client: GET exchange/rest/ms/xml/CustomEntityMetadata/uuid {}
# => [Moysklad::Entities::CustomEntityMetadata]
Значения всех элементов пользовательского справочника:
dictionary.entities(universe)
# => [Moysklad::Entities::CustomEntity, ...]
Подробнее смотри в исходниках сущностей.
Pull Requests
Добавление новых моделей и ресурсов.
На данный момен в библиотеку добавлено 60% справочников используемых в моемскладе. Я добавляю новые справочники по мере необходимости. Но вы можете это сделать и сами следующим образом.
Например добавляем Country
.
-
Добавляем в фикстуры пример выгрузки из API для тестирования и отладки:
MS_LOGON=логин MS_PASSWORD=пароль ./scripts/rest.sh Country list > ./spec/fixtures/Country_list.raw
-
Создаем сущность на основе уже существующей, например good.rb
cp ./lib/moysklad/entities/good.rb ./lib/moysklad/entities/country.rb
-
Описываем свойства новой сущности Country.rb в терминах nokogiri-happymapper-а
vi ./lib/moysklad/entities/country.rb
-
Добавляем сущность в requirements
vi ./lib/moysklad/entities.rb
-
Содаем автоматический ресурс (имя ресурса во множественном числе)
vi ./lib/moysklad/resources.rb
-
Делаем spec для сущности и для ресурса.
vi ./spec/lib/moysklad/resources/countries_spec.rb vi ./spec/lib/moysklad/entities/country_spec.rb
-
Проверяем что тесты проходят.
-
Присылаем Pull Request
Тестирование
> bundle exec guard
Полезняшки
Скрипт для быстрого доступа к сервисам моего склада
> MS_LOGON=логин MS_PASSWORD=пароль ./script/rest.sh Country list > ./spec/fixtures/Country_list.raw
Если получаете 429 ошибку (too many requests) - лимит обращений по API от одного аккаунта - 5 или 10 запросов в секунду (в секунду, Карл). Если не превышать его, все будет хорошо - минутных или часовых лимитов нет.
HTTP Таймаут
По-умолчанию таймаут равен 120 секунд, но его можно менять через переменную
окружения MOYSKLAD_HTTP_TIMEOUT
Ссылочки
- Картапамяти по API http://www.mindmeister.com/246618635/online-moysklad-ru
- Документация для разработчииков https://support.moysklad.ru/hc/ru/sections/200561443-Разработчикам
- Неплохая схема API в json https://gist.github.com/dapi/22a0790db19a4ff51a37
Другие биллиотеки
- PHP https://github.com/Tooyz/moysklad
- JavaScript/nodejs https://github.com/wmakeev/moysklad-client
Присылайте пул-реквесты )
Авторство
- Данил Письменный (brandymint.ru)