Ruby-клиент для REST XML API Moysklad

Build Status Dependency Status Code Climate

Особенности

  • Модуль разработан согласно принципам 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..subresource_by_name(:GoodFolder).all
# => [Moysklad::Entities::AttributeMetadata, Moysklad::Entities::AttributeMetadata]

Или получить конкретное свойство:

universe..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. universe
# Client: GET exchange/rest/ms/xml/Metadata/list {}
# => [Moysklad::Entities::AttributeMetadata]

Получаем описание пользовательского справочника к которому принадлежит свойства

dictionary = attribute.(universe).(universe)
# Client: GET exchange/rest/ms/xml/CustomEntityMetadata/uuid {}
# => [Moysklad::Entities::CustomEntityMetadata]

Значения всех элементов пользовательского справочника:

dictionary.entities(universe)
# => [Moysklad::Entities::CustomEntity, ...]

Подробнее смотри в исходниках сущностей.

Pull Requests

Добавление новых моделей и ресурсов.

На данный момен в библиотеку добавлено 60% справочников используемых в моемскладе. Я добавляю новые справочники по мере необходимости. Но вы можете это сделать и сами следующим образом.

Например добавляем Country.

  1. Добавляем в фикстуры пример выгрузки из API для тестирования и отладки:

    MS_LOGON=логин MS_PASSWORD=пароль ./scripts/rest.sh Country list > ./spec/fixtures/Country_list.raw

  2. Создаем сущность на основе уже существующей, например good.rb

    cp ./lib/moysklad/entities/good.rb ./lib/moysklad/entities/country.rb

  3. Описываем свойства новой сущности Country.rb в терминах nokogiri-happymapper

    vi ./lib/moysklad/entities/country.rb

  4. Добавляем сущность в requirements

    vi ./lib/moysklad/entities.rb

  5. Содаем автоматический ресурс (имя ресурса во множественном числе)

    vi ./lib/moysklad/resources.rb

  6. Делаем spec для сущности и для ресурса.

    vi ./spec/lib/moysklad/resources/countries_spec.rb vi ./spec/lib/moysklad/entities/country_spec.rb

  7. Проверяем что тесты проходят.

  8. Присылаем 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

Ссылочки

Другие биллиотеки

Присылайте пул-реквесты )

Авторство

  • Данил Письменный (brandymint.ru)