moysklad 0.2.1 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/rspec.yml +29 -0
- data/.gitignore +1 -0
- data/README.md +14 -3
- data/lib/moysklad/client/errors.rb +60 -30
- data/lib/moysklad/client.rb +39 -11
- data/lib/moysklad/entities/assortment.rb +4 -0
- data/lib/moysklad/entities/attribute.rb +111 -37
- data/lib/moysklad/entities/attribute_metadata.rb +7 -31
- data/lib/moysklad/entities/attribute_value.rb +18 -0
- data/lib/moysklad/entities/base.rb +23 -8
- data/lib/moysklad/entities/bundle.rb +39 -0
- data/lib/moysklad/entities/characteristic.rb +4 -0
- data/lib/moysklad/entities/characteristic_metadata.rb +4 -0
- data/lib/moysklad/entities/collection.rb +27 -7
- data/lib/moysklad/entities/collection_meta.rb +11 -0
- data/lib/moysklad/entities/company_settings_metadata.rb +26 -0
- data/lib/moysklad/entities/consignment.rb +16 -17
- data/lib/moysklad/entities/context.rb +7 -0
- data/lib/moysklad/entities/counterparty.rb +20 -0
- data/lib/moysklad/entities/country.rb +2 -8
- data/lib/moysklad/entities/currency.rb +27 -0
- data/lib/moysklad/entities/custom_entity.rb +17 -10
- data/lib/moysklad/entities/customer_order.rb +109 -23
- data/lib/moysklad/entities/customer_order_position.rb +6 -18
- data/lib/moysklad/entities/employee.rb +5 -0
- data/lib/moysklad/entities/entity.rb +39 -0
- data/lib/moysklad/entities/group.rb +10 -0
- data/lib/moysklad/entities/image.rb +16 -0
- data/lib/moysklad/entities/meta.rb +12 -0
- data/lib/moysklad/entities/organization.rb +17 -0
- data/lib/moysklad/entities/owner.rb +4 -0
- data/lib/moysklad/entities/price.rb +4 -8
- data/lib/moysklad/entities/price_type.rb +0 -8
- data/lib/moysklad/entities/product.rb +47 -0
- data/lib/moysklad/entities/productfolder.rb +11 -0
- data/lib/moysklad/entities/rate.rb +6 -0
- data/lib/moysklad/entities/resource_metadata.rb +8 -0
- data/lib/moysklad/entities/service.rb +23 -0
- data/lib/moysklad/entities/shortcut.rb +9 -0
- data/lib/moysklad/entities/store.rb +9 -0
- data/lib/moysklad/entities/time.rb +13 -0
- data/lib/moysklad/entities/uom.rb +5 -0
- data/lib/moysklad/entities/variant.rb +47 -0
- data/lib/moysklad/entities.rb +42 -39
- data/lib/moysklad/error.rb +1 -0
- data/lib/moysklad/resources/assortments.rb +13 -0
- data/lib/moysklad/resources/base.rb +35 -46
- data/lib/moysklad/resources/custom_entities.rb +29 -0
- data/lib/moysklad/resources/custom_entity_metadata.rb +12 -8
- data/lib/moysklad/resources/embedded_entity_metadata.rb +2 -3
- data/lib/moysklad/resources/indexed.rb +21 -37
- data/lib/moysklad/resources/indexed_cache.rb +36 -0
- data/lib/moysklad/resources/load_all.rb +21 -0
- data/lib/moysklad/resources/positions.rb +15 -0
- data/lib/moysklad/resources/products.rb +10 -0
- data/lib/moysklad/resources/stock.rb +1 -1
- data/lib/moysklad/resources/subresource.rb +0 -1
- data/lib/moysklad/resources/where_filter.rb +0 -1
- data/lib/moysklad/resources.rb +26 -11
- data/lib/moysklad/universe.rb +16 -2
- data/lib/moysklad/version.rb +1 -1
- data/lib/moysklad.rb +12 -7
- data/moysklad.gemspec +5 -3
- data/scripts/rest.sh +5 -2
- data/spec/lib/moysklad/entities/customer_order_position_spec.rb +4 -17
- data/spec/lib/moysklad/entities/customer_order_spec.rb +8 -33
- data/spec/lib/moysklad/resources/base_spec.rb +0 -54
- data/spec/lib/moysklad/resources_spec.rb +0 -2
- data/spec/lib/moysklad/universe_spec.rb +0 -23
- data/spec/lib/moysklad_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/support/resource.rb +1 -66
- data/test.rb +177 -0
- metadata +89 -172
- data/.travis.yml +0 -4
- data/lib/moysklad/entities/barcode.rb +0 -13
- data/lib/moysklad/entities/common.rb +0 -15
- data/lib/moysklad/entities/common_object.rb +0 -29
- data/lib/moysklad/entities/company.rb +0 -20
- data/lib/moysklad/entities/company_concern.rb +0 -20
- data/lib/moysklad/entities/contact.rb +0 -15
- data/lib/moysklad/entities/custom_entity_metadata.rb +0 -36
- data/lib/moysklad/entities/embedded_entity_metadata.rb +0 -18
- data/lib/moysklad/entities/error.rb +0 -13
- data/lib/moysklad/entities/feature.rb +0 -20
- data/lib/moysklad/entities/good.rb +0 -34
- data/lib/moysklad/entities/good_folder.rb +0 -9
- data/lib/moysklad/entities/good_ref.rb +0 -12
- data/lib/moysklad/entities/my_company.rb +0 -12
- data/lib/moysklad/entities/sale_price.rb +0 -18
- data/lib/moysklad/entities/sale_prices.rb +0 -10
- data/lib/moysklad/entities/slot.rb +0 -10
- data/lib/moysklad/entities/stock_to.rb +0 -33
- data/lib/moysklad/entities/warehouse.rb +0 -15
- data/lib/moysklad/entities/xml_fix.rb +0 -15
- data/spec/fixtures/302.raw +0 -15
- data/spec/fixtures/400.raw +0 -8
- data/spec/fixtures/401.html +0 -1
- data/spec/fixtures/401_2.html +0 -1
- data/spec/fixtures/405.raw +0 -9
- data/spec/fixtures/500.raw +0 -8
- data/spec/fixtures/502.raw +0 -8
- data/spec/fixtures/Consignment_list_0.raw +0 -14
- data/spec/fixtures/Consignment_list_1000.raw +0 -14
- data/spec/fixtures/Country_list.raw +0 -14
- data/spec/fixtures/CustomEntityMetadata_list.raw +0 -14
- data/spec/fixtures/CustomEntity_list.raw +0 -14
- data/spec/fixtures/CustomEntity_list_bad_chars.raw +0 -17
- data/spec/fixtures/EmbeddedEntityMetadata_list.raw +0 -15
- data/spec/fixtures/Feature_list.raw +0 -14
- data/spec/fixtures/Feature_list_1000.raw +0 -14
- data/spec/fixtures/Good_e932ebe1-2e22-11e4-9406-002590a28eca.raw +0 -12
- data/spec/fixtures/Good_eb77ad57-2e22-11e4-4030-002590a28eca.raw +0 -12
- data/spec/fixtures/Goods_list.raw +0 -14
- data/spec/fixtures/Metadata_list.raw +0 -14
- data/spec/fixtures/PriceType_list.raw +0 -14
- data/spec/fixtures/Stock.raw +0 -11
- data/spec/fixtures/Stock_showConsignments.raw +0 -11
- data/spec/fixtures/Uom_list.raw +0 -14
- data/spec/fixtures/Warehouse_list.raw +0 -14
- data/spec/fixtures/attribute_boolean.xml +0 -6
- data/spec/fixtures/attribute_dictionary.xml +0 -5
- data/spec/fixtures/attribute_double.xml +0 -6
- data/spec/fixtures/attribute_file.xml +0 -12
- data/spec/fixtures/attribute_long.xml +0 -6
- data/spec/fixtures/attribute_text.xml +0 -5
- data/spec/fixtures/attribute_time.xml +0 -6
- data/spec/fixtures/attribute_url.xml +0 -6
- data/spec/fixtures/bad_chars.xml +0 -6
- data/spec/fixtures/customer_order.xml +0 -28
- data/spec/fixtures/good_with_attributes.raw +0 -12
- data/spec/fixtures/resource_forbidden.raw +0 -9
- data/spec/fixtures/wrong_password.raw +0 -9
- data/spec/fixtures/wrong_type.raw +0 -70
- data/spec/fixtures/wrong_user.raw +0 -9
- data/spec/lib/moysklad/client/errors_spec.rb +0 -102
- data/spec/lib/moysklad/entities/attribute_metadata_spec.rb +0 -30
- data/spec/lib/moysklad/entities/attribute_spec.rb +0 -36
- data/spec/lib/moysklad/entities/country_spec.rb +0 -25
- data/spec/lib/moysklad/entities/custom_entity_metadata_spec.rb +0 -34
- data/spec/lib/moysklad/entities/custom_entity_spec.rb +0 -34
- data/spec/lib/moysklad/entities/good_spec.rb +0 -46
- data/spec/lib/moysklad/resources/countries_spec.rb +0 -22
- data/spec/lib/moysklad/resources/custom_entity_metadata_spec.rb +0 -13
- data/spec/lib/moysklad/resources/embedded_entity_metadata_indexed_spec.rb +0 -20
- data/spec/lib/moysklad/resources/embedded_entity_metadata_spec.rb +0 -11
- data/spec/lib/moysklad/resources/good_folders_spec.rb +0 -17
- data/spec/lib/moysklad/resources/indexed_spec.rb +0 -61
- data/spec/lib/moysklad/resources/stock_spec.rb +0 -63
- data/spec/lib/moysklad/resources/warehouses_spec.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6fad3cc93541b8fa239ed1a6e3e7a900d2206117589163067f85289abb0261b3
|
4
|
+
data.tar.gz: bc7c87f9765092342522ffba77d6178c00f670e4e8f5363f77f7055c17a80f9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2149b17c96a6dcf5a8006f16173739caeb4745f0055921d548d46b9c084a4fc083d6f644e6ff6407cdd7f0563be0fdff43f84e37b3b7a7c77568a16127b09ad6
|
7
|
+
data.tar.gz: 5f3ad953ea673c0e69d1fef4405ab5711e8cd603c88a93fa57ac49cda7f2fd8353723da25abcc6b54076416dbc5b5858ed39d1738cb223cde9414a200505126d
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Rspec
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
steps:
|
20
|
+
- name: Checkout repository and submodules
|
21
|
+
uses: actions/checkout@v2
|
22
|
+
with:
|
23
|
+
submodules: recursive
|
24
|
+
- name: Set up Ruby
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: 3.1.4
|
28
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
29
|
+
- run: bundle exec rspec
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Ruby-клиент для REST XML API Moysklad
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/BrandyMint/moysklad.svg)](https://travis-ci.org/
|
3
|
+
[![Build Status](https://travis-ci.org/BrandyMint/moysklad.svg)](https://travis-ci.org/dapi/moysklad)
|
4
4
|
[![Dependency Status](https://www.versioneye.com/user/projects/548225818674a4b5b90004dd/badge.svg?style=flat)](https://www.versioneye.com/user/projects/548225818674a4b5b90004dd)
|
5
|
-
[![Code Climate](https://codeclimate.com/github/
|
5
|
+
[![Code Climate](https://codeclimate.com/github/dapi/moysklad/badges/gpa.svg)](https://codeclimate.com/github/dapi/moysklad)
|
6
6
|
|
7
7
|
* http://www.rubydoc.info/gems/moysklad
|
8
8
|
|
@@ -12,8 +12,9 @@
|
|
12
12
|
* Все используемые сущности описаны и структурированы. Например [Good](lib/moysklad/entities/good.rb)
|
13
13
|
* Любые действия с ресурсами (Create, Read, Update, Delete, List).
|
14
14
|
* Виртуальные действия с ресурсами (`where`, `findWhere`)
|
15
|
+
* Автоматическая подгрузка списка если все данные не уместились в один запрос (метод `all`)
|
15
16
|
* _Кеширование и предзагрузка_ ресурса со всеми записями (используем ресурс как локальную базу)
|
16
|
-
* Работа с нескольмими аккаунтами
|
17
|
+
* Работа с нескольмими аккаунтами склада одновременно (отсуствие глобальных переменных).
|
17
18
|
* Удобная работа с подресурсами (например справочником свойств товара)
|
18
19
|
* _Ассоциации_ между сущностями автоматически получают данные по API (`good.features`).
|
19
20
|
* [Client](lib/moysklad/client.rb) для прямого обращения к API в случае крайней необходимости.
|
@@ -282,10 +283,20 @@ dictionary.entities(universe)
|
|
282
283
|
|
283
284
|
> MS_LOGON=логин MS_PASSWORD=пароль ./script/rest.sh Country list > ./spec/fixtures/Country_list.raw
|
284
285
|
|
286
|
+
Если получаете 429 ошибку (too many requests) - лимит обращений по API от одного
|
287
|
+
аккаунта - 5 или 10 запросов в секунду (в секунду, Карл). Если не превышать его,
|
288
|
+
все будет хорошо - минутных или часовых лимитов нет.
|
289
|
+
|
285
290
|
## Ссылочки
|
286
291
|
|
287
292
|
* Картапамяти по API http://www.mindmeister.com/246618635/online-moysklad-ru
|
288
293
|
* Документация для разработчииков https://support.moysklad.ru/hc/ru/sections/200561443-Разработчикам
|
294
|
+
* Неплохая схема API в json https://gist.github.com/dapi/22a0790db19a4ff51a37
|
295
|
+
|
296
|
+
## Другие биллиотеки
|
297
|
+
|
298
|
+
* PHP https://github.com/Tooyz/moysklad
|
299
|
+
* JavaScript/nodejs https://github.com/wmakeev/moysklad-client
|
289
300
|
|
290
301
|
## Присылайте пул-реквесты )
|
291
302
|
|
@@ -1,23 +1,44 @@
|
|
1
1
|
class Moysklad::Client
|
2
2
|
class Errors
|
3
3
|
def self.build res
|
4
|
-
|
4
|
+
body = res.body.force_encoding('utf-8')
|
5
|
+
content_type = res.headers['content-type']
|
6
|
+
|
7
|
+
if content_type.start_with? 'application/json'
|
8
|
+
# ok
|
9
|
+
elsif content_type.start_with? 'text/html'
|
10
|
+
raise HtmlParsedError, body
|
11
|
+
else
|
12
|
+
raise UnknownError, body
|
13
|
+
end
|
14
|
+
|
15
|
+
# Encoding::UndefinedConversionError
|
16
|
+
# "\xD0" from ASCII-8BIT to UTF-8
|
17
|
+
begin
|
18
|
+
body = JSON.parse body
|
19
|
+
Moysklad.logger.debug "Moysklad::Client: #{res.status}: #{res.headers}, #{res.env.url.to_s}\n#{body}"
|
20
|
+
rescue Encoding::UndefinedConversionError => err
|
21
|
+
Moysklad.logger.error "#{err}"
|
22
|
+
rescue JSON::ParserError => err
|
23
|
+
Moysklad.logger.error "#{err}: #{res.headers}, body:#{body}"
|
24
|
+
raise ParsingError, body
|
25
|
+
end
|
5
26
|
|
6
27
|
case res.status
|
7
|
-
when 401
|
8
|
-
raise UnauthorizedError.new
|
28
|
+
when 401
|
29
|
+
raise UnauthorizedError.new body
|
9
30
|
when 403
|
10
|
-
raise ResourceForbidden.new
|
11
|
-
when 404
|
12
|
-
raise NoResourceFound.new
|
13
|
-
when 405
|
14
|
-
raise MethodNotAllowedError.new
|
31
|
+
raise ResourceForbidden.new body
|
32
|
+
when 404
|
33
|
+
raise NoResourceFound.new body
|
34
|
+
when 405, 412
|
35
|
+
raise MethodNotAllowedError.new body
|
15
36
|
when 500
|
16
|
-
raise InternalServerError.new
|
37
|
+
raise InternalServerError.new body
|
17
38
|
when 502
|
18
|
-
raise BadGatewayError.new
|
19
|
-
else
|
20
|
-
raise
|
39
|
+
raise BadGatewayError.new body
|
40
|
+
else
|
41
|
+
raise JsonParsedError.new body
|
21
42
|
end
|
22
43
|
end
|
23
44
|
end
|
@@ -32,39 +53,48 @@ class Moysklad::Client
|
|
32
53
|
end
|
33
54
|
|
34
55
|
def to_s
|
35
|
-
message
|
56
|
+
message.to_s.encode('utf-8')
|
57
|
+
# <?xml version="1.0" encoding="UTF-8"?> <error> <uid>kiiiosk@wannabemoscow</uid> <moment>20150609112728449</moment> <message>������������ ���� ���������� �������� ������������.</message> </error>
|
58
|
+
rescue Encoding::CompatibilityError
|
59
|
+
message.to_s.force_encoding('cp1251').encode('utf-8')
|
36
60
|
end
|
37
61
|
end
|
62
|
+
class ParsingError < Error; end
|
63
|
+
|
64
|
+
class UnknownError < Error; end
|
38
65
|
|
39
66
|
class NoResourceFound < Error; end
|
40
67
|
|
68
|
+
class JsonParsedError < Error
|
69
|
+
def initialize result
|
70
|
+
super result.to_json
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :error
|
74
|
+
end
|
75
|
+
|
41
76
|
class HtmlParsedError < Error
|
42
|
-
def initialize
|
43
|
-
@
|
44
|
-
@message = "[#{res.status}] #{parse_title res.body}"
|
77
|
+
def initialize body
|
78
|
+
@message = parse_title body
|
45
79
|
end
|
46
80
|
|
47
81
|
private
|
48
82
|
|
49
83
|
def parse_title body
|
50
|
-
|
51
|
-
# у ResourceForbidden есть <u>
|
52
|
-
# у wrong_password <u> несколько
|
53
|
-
# Можно ошибку разбирать более грамотно по свойствам type, message, description: http://i.gyazo.com/e9d5d08bd610882d87f39d9002cdf25a.png
|
54
|
-
[doc.css('body').css('h1').text,doc.css('body').css('u').to_a.map(&:text).compact.last].join('; ')
|
84
|
+
Nokogiri::HTML(body).css('body').text
|
55
85
|
rescue => err
|
56
|
-
Moysklad.logger.debug "
|
86
|
+
Moysklad.logger.debug "Moysklad::Client parse error #{err}: #{body}"
|
57
87
|
body.force_encoding('utf-8')
|
58
88
|
end
|
59
89
|
end
|
60
90
|
|
61
|
-
class MethodNotAllowedError <
|
91
|
+
class MethodNotAllowedError < JsonParsedError
|
62
92
|
end
|
63
93
|
|
64
|
-
class UnauthorizedError <
|
94
|
+
class UnauthorizedError < JsonParsedError
|
65
95
|
end
|
66
96
|
|
67
|
-
class ResourceForbidden <
|
97
|
+
class ResourceForbidden < JsonParsedError
|
68
98
|
end
|
69
99
|
|
70
100
|
class ParsedError < Error
|
@@ -72,24 +102,24 @@ class Moysklad::Client
|
|
72
102
|
@status = result.status
|
73
103
|
@result = result
|
74
104
|
case result.headers['content-type']
|
75
|
-
|
105
|
+
|
76
106
|
when /application\/xml/
|
77
107
|
@error = Moysklad::Entities::Error.parse result.body
|
78
108
|
@message = @error.message
|
79
109
|
when /text\/html/
|
80
|
-
doc = Nokogiri::HTML body
|
110
|
+
doc = Nokogiri::HTML result.body
|
81
111
|
@message = doc.css('body').css('h1').text
|
82
112
|
else
|
83
113
|
raise "Unknown content-type #{result.headers['content-type']} to parse error #{result.body}"
|
84
114
|
end
|
85
115
|
rescue => err
|
86
|
-
@message = "error in init #{err}: #{result
|
116
|
+
@message = "error in init #{err}: #{result}"
|
87
117
|
end
|
88
118
|
|
89
119
|
attr_reader :error
|
90
120
|
end
|
91
121
|
|
92
122
|
|
93
|
-
class BadGatewayError <
|
94
|
-
class InternalServerError <
|
123
|
+
class BadGatewayError < JsonParsedError; end
|
124
|
+
class InternalServerError < JsonParsedError; end
|
95
125
|
end
|
data/lib/moysklad/client.rb
CHANGED
@@ -4,31 +4,55 @@ require_relative 'client/errors'
|
|
4
4
|
|
5
5
|
class Moysklad::Client
|
6
6
|
|
7
|
-
URL = 'https://online.moysklad.ru'
|
7
|
+
# URL = 'https://online.moysklad.ru'
|
8
|
+
URL ='https://online.moysklad.ru/api/remap/1.1/'
|
8
9
|
|
9
10
|
def initialize login: nil, password: nil
|
10
|
-
@client = Faraday.new URL
|
11
|
-
|
11
|
+
@client = Faraday.new URL do |conn|
|
12
|
+
conn.request(:authorization, :basic, login, password)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def download(path, filename)
|
17
|
+
response = client.get path
|
18
|
+
File.open(filename, 'wb') { |fp| fp.write(response.body) }
|
12
19
|
end
|
13
20
|
|
14
21
|
def get path, params={}
|
15
22
|
logger.debug "Client: GET #{path} #{params}"
|
16
|
-
|
23
|
+
parse_response client.get path, params
|
24
|
+
end
|
25
|
+
|
26
|
+
def post path, data
|
27
|
+
logger.debug "Client: POST #{path}"
|
28
|
+
result = client.post do |req|
|
29
|
+
req.url path
|
30
|
+
req.headers['Content-Type'] = 'application/json'
|
31
|
+
req.headers['Accept'] = '*/*'
|
32
|
+
req.body = data
|
33
|
+
end
|
34
|
+
parse_response result
|
17
35
|
end
|
18
36
|
|
19
37
|
def put path, data
|
20
38
|
logger.debug "Client: PUT #{path}"
|
21
39
|
result = client.put do |req|
|
22
40
|
req.url path
|
23
|
-
req.headers['Content-Type'] = 'application/
|
41
|
+
req.headers['Content-Type'] = 'application/json'
|
24
42
|
req.headers['Accept'] = '*/*'
|
25
43
|
req.body = data
|
26
44
|
end
|
27
|
-
|
45
|
+
parse_response result
|
28
46
|
end
|
29
47
|
|
30
48
|
def delete path
|
31
|
-
|
49
|
+
logger.debug "Client: DELETE #{path}"
|
50
|
+
result = client.delete do |req|
|
51
|
+
req.url path
|
52
|
+
req.headers['Content-Type'] = 'application/json'
|
53
|
+
req.headers['Accept'] = '*/*'
|
54
|
+
end
|
55
|
+
parse_response result
|
32
56
|
end
|
33
57
|
|
34
58
|
private
|
@@ -39,10 +63,14 @@ class Moysklad::Client
|
|
39
63
|
Moysklad.logger
|
40
64
|
end
|
41
65
|
|
42
|
-
def
|
43
|
-
|
66
|
+
def parse_response res
|
67
|
+
Moysklad.logger.debug "Response [#{res.status}]: #{res.body}"
|
44
68
|
|
45
|
-
|
69
|
+
if res.status == 200
|
70
|
+
return if res.body.blank?
|
71
|
+
JSON.parse res.body
|
72
|
+
else
|
73
|
+
Moysklad::Client::Errors.build res
|
74
|
+
end
|
46
75
|
end
|
47
|
-
|
48
76
|
end
|
@@ -1,47 +1,121 @@
|
|
1
|
+
# Атрибут товара (ссылка на его тип и его значение)
|
1
2
|
module Moysklad::Entities
|
2
3
|
class Attribute < Base
|
3
|
-
|
4
|
+
attribute :meta, Meta
|
5
|
+
attribute :id, String
|
6
|
+
attribute :name, String
|
7
|
+
attribute :customEntityMeta, Meta
|
8
|
+
attribute :type, String #attributemetadata
|
9
|
+
attribute :value, AttributeValue
|
10
|
+
attribute :required, Boolean
|
4
11
|
|
5
|
-
|
12
|
+
def to_s
|
13
|
+
"#{name} (#{type}): #{value}"
|
14
|
+
end
|
6
15
|
|
7
|
-
|
8
|
-
|
9
|
-
|
16
|
+
def is_dictionary?
|
17
|
+
type == 'customentity'
|
18
|
+
end
|
10
19
|
|
11
|
-
|
20
|
+
### Если это свойство типа ID_CUSTOM, то возвращается пользовательский справочник
|
21
|
+
###
|
22
|
+
### @return Moysklad::Entities::CustomEntityMetadata
|
23
|
+
##def dictionatyMetadata universe
|
24
|
+
##raise "Это свойства не типа справочник" unless dictionaryMetadataUuid
|
25
|
+
##universe.custom_entity_metadata.find dictionaryMetadataUuid
|
26
|
+
##end
|
12
27
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
28
|
+
### Справочник к которому принадлежит это ссвойство
|
29
|
+
###
|
30
|
+
### @return Moysklad::Entities::EmbeddedEntityMetadata
|
31
|
+
##def entityMetadata universe
|
32
|
+
##universe.embedded_entity_metadata.find entityMetadataUuid
|
33
|
+
##end
|
20
34
|
|
21
|
-
# Название свойства, полученное из AttributeMetadata
|
22
|
-
#
|
23
|
-
# @return String
|
24
|
-
#
|
25
|
-
def attributeName universe
|
26
|
-
metadata(universe).name
|
27
|
-
end
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
### Объект описывающий тип атритуба
|
37
|
+
###
|
38
|
+
### @return Moysklad::Entities::AttributeMetadata
|
39
|
+
###
|
40
|
+
##def metadata universe
|
41
|
+
##universe.embedded_entity_metadata.subresource_by_name(:GoodFolder).find metadataUuid
|
42
|
+
##end
|
43
|
+
|
44
|
+
### Название свойства, полученное из AttributeMetadata
|
45
|
+
###
|
46
|
+
### @return String
|
47
|
+
###
|
48
|
+
##def attributeName universe
|
49
|
+
##metadata(universe).name
|
50
|
+
##end
|
51
|
+
|
52
|
+
### Значение свойства согласно его типу
|
53
|
+
###
|
54
|
+
### @return [String | Moysklad::Entities::CustomEntity | Integer | Decimal ]
|
55
|
+
#def get_value universe
|
56
|
+
#md = metadata universe
|
57
|
+
#case md.attrType
|
58
|
+
#when 'ID_CUSTOM'
|
59
|
+
#universe.custom_entities.find( entityValueUuid ).name
|
60
|
+
#when 'LINK'
|
61
|
+
#valueText
|
62
|
+
#when 'TEXT'
|
63
|
+
#valueText
|
64
|
+
#when 'STRING'
|
65
|
+
#valueString
|
66
|
+
#when 'DOUBLE'
|
67
|
+
#doubleValue
|
68
|
+
#when 'LONG'
|
69
|
+
#longValue
|
70
|
+
#when 'TIME'
|
71
|
+
#timeValue
|
72
|
+
#when 'FILE'
|
73
|
+
#file
|
74
|
+
#else
|
75
|
+
#raise "Не известный тип мета-аттрибута #{md.uuid}: #{md.attrType}"
|
76
|
+
#end
|
77
|
+
#end
|
78
|
+
### Объект описывающий тип атритуба
|
79
|
+
###
|
80
|
+
### @return Moysklad::Entities::AttributeMetadata
|
81
|
+
###
|
82
|
+
##def metadata universe
|
83
|
+
##universe.embedded_entity_metadata.subresource_by_name(:GoodFolder).find metadataUuid
|
84
|
+
##end
|
85
|
+
|
86
|
+
### Название свойства, полученное из AttributeMetadata
|
87
|
+
###
|
88
|
+
### @return String
|
89
|
+
###
|
90
|
+
##def attributeName universe
|
91
|
+
##metadata(universe).name
|
92
|
+
##end
|
93
|
+
|
94
|
+
### Значение свойства согласно его типу
|
95
|
+
###
|
96
|
+
### @return [String | Moysklad::Entities::CustomEntity | Integer | Decimal ]
|
97
|
+
##def get_value universe
|
98
|
+
##md = metadata universe
|
99
|
+
##case md.attrType
|
100
|
+
##when 'ID_CUSTOM'
|
101
|
+
##universe.custom_entities.find( entityValueUuid ).name
|
102
|
+
##when 'LINK'
|
103
|
+
##valueText
|
104
|
+
##when 'TEXT'
|
105
|
+
##valueText
|
106
|
+
##when 'STRING'
|
107
|
+
##valueString
|
108
|
+
##when 'DOUBLE'
|
109
|
+
##doubleValue
|
110
|
+
##when 'LONG'
|
111
|
+
##longValue
|
112
|
+
##when 'TIME'
|
113
|
+
##timeValue
|
114
|
+
##when 'FILE'
|
115
|
+
##file
|
116
|
+
##else
|
117
|
+
##raise "Не известный тип мета-аттрибута #{md.uuid}: #{md.attrType}"
|
118
|
+
##end
|
119
|
+
##end
|
46
120
|
end
|
47
121
|
end
|
@@ -1,38 +1,14 @@
|
|
1
1
|
module Moysklad::Entities
|
2
|
-
# https://online.moysklad.ru/exchange/rest/ms/xml/Metadata/list
|
3
2
|
class AttributeMetadata < Base
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# STRING
|
11
|
-
attribute :attrType, String
|
12
|
-
attribute :entityMetadataUuid, String
|
13
|
-
attribute :feature, Boolean
|
14
|
-
attribute :position, Integer
|
15
|
-
attribute :required, Boolean
|
16
|
-
attribute :dictionaryMetadataUuid, String
|
3
|
+
attribute :meta, Meta
|
4
|
+
attribute :id, String
|
5
|
+
attribute :name, String
|
6
|
+
attribute :type, String # string, customentity
|
7
|
+
attribute :required, Boolean
|
8
|
+
attribute :customEntityMeta, Meta
|
17
9
|
|
18
10
|
def is_dictionary?
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
# Если это свойство типа ID_CUSTOM, то возвращается пользовательский справочник
|
23
|
-
#
|
24
|
-
# @return Moysklad::Entities::CustomEntityMetadata
|
25
|
-
def dictionatyMetadata universe
|
26
|
-
raise "Это свойства не типа справочник" unless dictionaryMetadataUuid
|
27
|
-
universe.custom_entity_metadata.find dictionaryMetadataUuid
|
11
|
+
type == 'customentity'
|
28
12
|
end
|
29
|
-
|
30
|
-
# Справочник к которому принадлежит это ссвойство
|
31
|
-
#
|
32
|
-
# @return Moysklad::Entities::EmbeddedEntityMetadata
|
33
|
-
def entityMetadata universe
|
34
|
-
universe.embedded_entity_metadata.find entityMetadataUuid
|
35
|
-
end
|
36
|
-
|
37
13
|
end
|
38
14
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Moysklad::Entities
|
2
|
+
class AttributeValue < Virtus::Attribute
|
3
|
+
def coerce(value)
|
4
|
+
case value
|
5
|
+
when String, Float
|
6
|
+
value
|
7
|
+
when ::Hash
|
8
|
+
if value['meta']['type'] == 'customentity'
|
9
|
+
CustomEntity.new value
|
10
|
+
else
|
11
|
+
raise "Unknown meta type: #{value['meta']['type']}"
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise "Unknown value type (#{value}) #{value.class}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,16 +1,31 @@
|
|
1
1
|
module Moysklad::Entities
|
2
2
|
class Base
|
3
|
-
|
3
|
+
include Virtus.model
|
4
|
+
attr_accessor :universe
|
5
|
+
attr_accessor :dump
|
4
6
|
|
5
|
-
|
7
|
+
def self.build(data, universe)
|
8
|
+
entity = new data
|
9
|
+
entity.universe = universe
|
10
|
+
entity
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(data = {})
|
14
|
+
data['attrs'] = data.delete 'attributes' if data['attributes']
|
15
|
+
super (data || {}).merge(dump: data)
|
16
|
+
end
|
6
17
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
18
|
+
def to_json(*args)
|
19
|
+
presented = {}
|
20
|
+
to_h.each_pair do |k, v|
|
21
|
+
presented[k] = v unless v.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
presented.to_json
|
25
|
+
end
|
11
26
|
|
12
|
-
|
13
|
-
|
27
|
+
def to_s
|
28
|
+
attributes.to_s
|
14
29
|
end
|
15
30
|
end
|
16
31
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Moysklad::Entities
|
2
|
+
# Комплект
|
3
|
+
# https://online.moysklad.ru/api/remap/1.1/doc/index.html#комплект
|
4
|
+
class Bundle < Product
|
5
|
+
#meta - Метаданные объекта
|
6
|
+
#id - ID Комплекта в формате UUID Только для чтения
|
7
|
+
#accountId - ID учетной записи Только для чтения
|
8
|
+
#owner - Ссылка на Владельца (Сотрудника) в формате Метаданных
|
9
|
+
#shared - Общий доступ
|
10
|
+
#group - Отдел сотрудника в формате Метаданных
|
11
|
+
#syncId - ID синхронизации Только для чтения
|
12
|
+
#version - Версия сущности Только для чтения
|
13
|
+
#updated - Момент последнего обновления сущности Только для чтения
|
14
|
+
#name - Наименование Комплекта Необходимое
|
15
|
+
#description - Описание Комплекта
|
16
|
+
#code - Код Комплекта
|
17
|
+
#externalCode - Внешний код Комплекта
|
18
|
+
#archived - Отметка о том, добавлен ли Комплект в архив
|
19
|
+
#pathName - Наименование группы, в которую входит Комплект Только для чтения
|
20
|
+
#vat - НДС %
|
21
|
+
#effectiveVat - Реальный НДС % Только для чтения
|
22
|
+
#productFolder - Ссылка на группу Комплекта
|
23
|
+
#uom - Единицы измерения
|
24
|
+
#image - Изображение Комплекта Только для чтения
|
25
|
+
#minPrice - Минимальная цена
|
26
|
+
#salePrices - Цены продажи
|
27
|
+
#attributes - Коллекция доп. полей в формате Метаданных
|
28
|
+
#country - Ссылка на страну в формате Метаданных
|
29
|
+
#article - Артикул
|
30
|
+
#weight - Вес
|
31
|
+
#volume - Объём
|
32
|
+
#barcodes - Массив штрихкодов Комплекта
|
33
|
+
#overhead - Дополнительные расходы
|
34
|
+
#currency - Валюта доп расходов
|
35
|
+
#value - Значение доп расходов
|
36
|
+
#components - Компоненты Комплекта
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|