moysklad 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -0
  4. data/README.md +14 -3
  5. data/lib/moysklad.rb +3 -2
  6. data/lib/moysklad/client.rb +37 -10
  7. data/lib/moysklad/client/errors.rb +60 -30
  8. data/lib/moysklad/entities.rb +17 -21
  9. data/lib/moysklad/entities/assortment.rb +6 -0
  10. data/lib/moysklad/entities/attachment_document.rb +16 -0
  11. data/lib/moysklad/entities/attribute.rb +114 -37
  12. data/lib/moysklad/entities/attribute_metadata.rb +9 -31
  13. data/lib/moysklad/entities/attribute_value.rb +19 -0
  14. data/lib/moysklad/entities/barcode.rb +10 -4
  15. data/lib/moysklad/entities/base.rb +23 -8
  16. data/lib/moysklad/entities/bundle.rb +39 -0
  17. data/lib/moysklad/entities/characteristic.rb +6 -0
  18. data/lib/moysklad/entities/characteristic_metadata.rb +6 -0
  19. data/lib/moysklad/entities/collection.rb +30 -7
  20. data/lib/moysklad/entities/collection_meta.rb +11 -0
  21. data/lib/moysklad/entities/common_object.rb +0 -2
  22. data/lib/moysklad/entities/company_settings_metadata.rb +28 -0
  23. data/lib/moysklad/entities/consignment.rb +19 -17
  24. data/lib/moysklad/entities/context.rb +9 -0
  25. data/lib/moysklad/entities/counterparty.rb +18 -0
  26. data/lib/moysklad/entities/currency.rb +29 -0
  27. data/lib/moysklad/entities/custom_entity.rb +20 -10
  28. data/lib/moysklad/entities/custom_entity_metadata.rb +7 -32
  29. data/lib/moysklad/entities/customer_order.rb +116 -23
  30. data/lib/moysklad/entities/customer_order_position.rb +10 -18
  31. data/lib/moysklad/entities/employee.rb +7 -0
  32. data/lib/moysklad/entities/entity.rb +42 -0
  33. data/lib/moysklad/entities/good_folder.rb +1 -0
  34. data/lib/moysklad/entities/group.rb +7 -0
  35. data/lib/moysklad/entities/image.rb +17 -0
  36. data/lib/moysklad/entities/images.rb +10 -0
  37. data/lib/moysklad/entities/meta.rb +14 -0
  38. data/lib/moysklad/entities/organization.rb +19 -0
  39. data/lib/moysklad/entities/owner.rb +4 -0
  40. data/lib/moysklad/entities/price.rb +5 -8
  41. data/lib/moysklad/entities/price_type.rb +2 -8
  42. data/lib/moysklad/entities/product.rb +54 -0
  43. data/lib/moysklad/entities/productfolder.rb +13 -0
  44. data/lib/moysklad/entities/rate.rb +9 -0
  45. data/lib/moysklad/entities/resource_metadata.rb +13 -0
  46. data/lib/moysklad/entities/service.rb +28 -0
  47. data/lib/moysklad/entities/shortcut.rb +11 -0
  48. data/lib/moysklad/entities/store.rb +10 -0
  49. data/lib/moysklad/entities/time.rb +13 -0
  50. data/lib/moysklad/entities/uom.rb +7 -0
  51. data/lib/moysklad/entities/variant.rb +51 -0
  52. data/lib/moysklad/entities/workflow.rb +11 -0
  53. data/lib/moysklad/entities/workflow_state.rb +8 -0
  54. data/lib/moysklad/error.rb +1 -0
  55. data/lib/moysklad/resources.rb +9 -7
  56. data/lib/moysklad/resources/assortments.rb +14 -0
  57. data/lib/moysklad/resources/base.rb +32 -44
  58. data/lib/moysklad/resources/custom_entities.rb +27 -0
  59. data/lib/moysklad/resources/custom_entity_metadata.rb +12 -8
  60. data/lib/moysklad/resources/embedded_entity_metadata.rb +0 -1
  61. data/lib/moysklad/resources/indexed.rb +23 -35
  62. data/lib/moysklad/resources/indexed_cache.rb +36 -0
  63. data/lib/moysklad/resources/load_all.rb +21 -0
  64. data/lib/moysklad/resources/products.rb +10 -0
  65. data/lib/moysklad/resources/where_filter.rb +0 -1
  66. data/lib/moysklad/universe.rb +16 -2
  67. data/lib/moysklad/version.rb +1 -1
  68. data/moysklad.gemspec +3 -1
  69. data/scripts/rest.sh +5 -2
  70. data/spec/fixtures/Good_WithManyAttributes.raw +13 -0
  71. data/spec/fixtures/Workflow_list.raw +15 -0
  72. data/spec/fixtures/good_with_image.xml +39 -0
  73. data/spec/lib/moysklad/entities/customer_order_spec.rb +7 -2
  74. data/spec/lib/moysklad/entities/good_spec.rb +9 -0
  75. data/spec/lib/moysklad/resources/workflows_spec.rb +21 -0
  76. data/spec/spec_helper.rb +2 -1
  77. data/test.rb +177 -0
  78. metadata +97 -44
  79. data/lib/moysklad/entities/common.rb +0 -15
  80. data/lib/moysklad/entities/feature.rb +0 -20
  81. data/lib/moysklad/entities/good.rb +0 -34
  82. data/lib/moysklad/entities/stock_to.rb +0 -33
  83. data/lib/moysklad/entities/warehouse.rb +0 -15
  84. data/lib/moysklad/entities/xml_fix.rb +0 -15
@@ -0,0 +1,13 @@
1
+ require_relative 'base'
2
+ require_relative 'attribute_metadata'
3
+ require_relative 'characteristic_metadata'
4
+ require_relative 'price_type'
5
+
6
+ module Moysklad::Entities
7
+ class ResourceMetadata < Base
8
+ attribute :meta, Meta
9
+ attribute :attrs, Array[AttributeMetadata]
10
+ attribute :characteristics, Array[CharacteristicMetadata]
11
+ attribute :priceTypes, Array[PriceType]
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ require_relative 'entity'
2
+ require_relative 'uom'
3
+ require_relative 'owner'
4
+ require_relative 'group'
5
+ require_relative 'price'
6
+
7
+ module Moysklad::Entities
8
+ class Service < Entity
9
+ attribute :accountId, String
10
+ attribute :owner, Owner
11
+ attribute :group, Group
12
+ attribute :vat, Float
13
+ attribute :effectiveVat, Float
14
+ attribute :pathName, String
15
+ attribute :productFolder, Productfolder
16
+
17
+ attribute :uom, Uom
18
+
19
+ attribute :minPrice, Float
20
+ attribute :salePrices, Array[Price]
21
+
22
+ # Когда загружаем через ассортименты эти поля устанавливаются
23
+ attribute :stock, Float
24
+ attribute :reserve, Float
25
+ attribute :inTransit, Float
26
+ attribute :quantity, Float
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'meta'
2
+
3
+ module Moysklad::Entities
4
+ class Shortcut < Base
5
+ attribute :meta, Meta
6
+
7
+ def id
8
+ meta.id
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'entity'
2
+ module Moysklad::Entities
3
+ class Store < Entity
4
+ attribute :address, String
5
+ attribute :description, String
6
+ attribute :parent, Hash
7
+ attribute :pathName, String
8
+ attribute :attrs, Array
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ class Moysklad::Entities::Time < Time
2
+ def to_json(*args)
3
+ to_s.to_json
4
+ end
5
+
6
+ def as_json(*args)
7
+ to_s
8
+ end
9
+
10
+ def to_s
11
+ strftime('%Y-%m-%d %H:%M:%S')
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'meta'
2
+
3
+ module Moysklad::Entities
4
+ class Uom < Base
5
+ attribute :meta, Meta
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ require_relative 'characteristic'
2
+ require_relative 'shortcut'
3
+ require_relative 'entity'
4
+
5
+ module Moysklad::Entities
6
+ class Variant < Entity
7
+
8
+ attribute :accountId, String
9
+
10
+ attribute :characteristics, Array[Characteristic]
11
+ attribute :minPrice, Float
12
+ attribute :buyPrice, Float
13
+ attribute :salePrices, Array[Price]
14
+ attribute :product, Shortcut
15
+ attribute :things, Array[String]
16
+
17
+ # Когда загружаем через ассортименты эти поля устанавливаются
18
+ attribute :stock, Float
19
+ attribute :reserve, Float
20
+ attribute :inTransit, Float
21
+ attribute :quantity, Float
22
+
23
+ #characteristics - Характеристики Модификации Необходимое
24
+ #minPrice - Минимальная цена
25
+ #buyPrice - Закупочная цена
26
+ #salePrices - Цены продажи
27
+ #product - Метаданные, представляющие с собой ссылку на товар, к которому привязана Модификация. Необходимое
28
+ #things - Серийные номера Только для чтения
29
+
30
+ #attribute :charactideristics,
31
+ #attribute :minPrice
32
+
33
+ #tag 'feature'
34
+
35
+ #attribute :goodUuid, String
36
+
37
+ #attribute :archived, Boolean
38
+ #attribute :isDefault, Boolean
39
+
40
+ #element :shared, Boolean
41
+
42
+ #has_many :attributes, Moysklad::Entities::Attribute
43
+ #has_many :barcodes, Moysklad::Entities::Barcode
44
+
45
+ #def good universe
46
+ #cache :good, universe do
47
+ #universe.good.find goodUuid
48
+ #end
49
+ #end
50
+ end
51
+ end
@@ -0,0 +1,11 @@
1
+ module Moysklad::Entities
2
+ class Workflow < Base
3
+ include CommonObject
4
+ include Moysklad::Entities::XmlFix
5
+
6
+ element :code, String
7
+ element :uuid, String
8
+
9
+ has_many :states, Moysklad::Entities::WorkflowState, tag: :state
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Moysklad::Entities
2
+ class WorkflowState < Base
3
+ include CommonObject
4
+ include Moysklad::Entities::XmlFix
5
+
6
+ element :uuid, String
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ Moysklad::Error = Class.new StandardError
@@ -10,15 +10,17 @@ module Moysklad::Resources
10
10
 
11
11
  require_relative 'resources/base'
12
12
  require_relative 'resources/indexed'
13
- require_relative 'resources/stock'
14
- require_relative 'resources/embedded_entity_metadata'
15
- require_relative 'resources/embedded_entity_metadata_indexed'
16
- require_relative 'resources/custom_entity_metadata'
17
- require_relative 'resources/subresource'
13
+ require_relative 'resources/custom_entities'
14
+ require_relative 'resources/assortments'
18
15
 
19
16
  # Простые ресурсы, которые создаются автоматически
20
- %w{Goods GoodFolders Uoms PriceType Countries Features CustomEntities CustomerOrders Warehouses Companies Consignments MyCompanies}.each do |klass_name|
17
+ %w{Products Productfolders Uoms PriceType Countries Variants
18
+ Counterparty
19
+ Organization
20
+ CustomerOrders Store
21
+ Currency
22
+ Workflows
23
+ Companies Consignments MyCompanies}.each do |klass_name|
21
24
  const_set klass_name, Class.new( Base )
22
25
  end
23
-
24
26
  end
@@ -0,0 +1,14 @@
1
+ require_relative 'load_all'
2
+ module Moysklad::Resources
3
+ class Assortments < Base
4
+ include LoadAll
5
+
6
+ def self.indexed(*args)
7
+ new(*args)
8
+ end
9
+
10
+ def all(params = {})
11
+ load_all(params)
12
+ end
13
+ end
14
+ end
@@ -1,7 +1,8 @@
1
+ require 'json'
1
2
  class Moysklad::Resources::Base
2
- PREFIX_PATH = 'exchange/rest/ms/xml/'
3
+ PREFIX_PATH = 'entity/'
3
4
 
4
- def self.inherited superclass
5
+ def self.inherited superclass
5
6
  super
6
7
  Moysklad::Resources.register_resource superclass
7
8
  end
@@ -14,30 +15,28 @@ class Moysklad::Resources::Base
14
15
  end
15
16
 
16
17
  # https://support.moysklad.ru/hc/ru/articles/203404253-REST-сервис-синхронизации-данных
17
- def initialize client: nil
18
+ def initialize client: nil, list_path: nil
19
+ @list_path = list_path
18
20
  raise "Должен быть Moysklad::Client" unless client.is_a? Moysklad::Client
19
21
  @client = client
20
22
  end
21
23
 
24
+ def metadata
25
+ Moysklad::Entities::ResourceMetadata.build client.get(metadata_path), self
26
+ end
27
+
22
28
  # Возвращает список элементов как есть
23
29
  #
24
30
  # @return [Array of Moysklad::Entities::Base]
25
31
  def list params={}
26
- parse client.get list_path, params
27
- end
28
-
29
- # Возвращает страницу со списком элементов
30
- #
31
- # @return [Moysklad::Entities::Page]
32
- def page params={}
33
- parse_page client.get list_path, params
32
+ load_collection client.get list_path, params
34
33
  end
35
34
 
36
35
  # Забираем элемент по uuid
37
36
  #
38
37
  # @return [Moysklad::Entities::Base]
39
- def get uuid
40
- parse client.get item_path uuid
38
+ def get uuid, params = {}
39
+ parse_get client.get item_path(uuid), params
41
40
  end
42
41
 
43
42
  # Модифицируем элемент по uuid
@@ -56,14 +55,14 @@ class Moysklad::Resources::Base
56
55
  # @return [Moysklad::Entities::Base]
57
56
  def create model
58
57
  raise "Должна быть модель типа Moysklad::Entities::Base" unless model.is_a? Moysklad::Entities::Base
59
- parse client.put create_path, prepare_resource(model)
58
+ parse_get client.post create_path, model.to_json
60
59
  end
61
60
 
62
61
  # Удаляем запись по uuid
63
62
  #
64
63
  # @param uuid
65
64
  def delete uuid
66
- client.delete item_path uuid
65
+ client.delete item_path uuid
67
66
  end
68
67
 
69
68
  def self.type
@@ -74,38 +73,16 @@ class Moysklad::Resources::Base
74
73
  ActiveSupport::Inflector.underscore ActiveSupport::Inflector.pluralize type
75
74
  end
76
75
 
77
- def self.entity_class
78
- ActiveSupport::Inflector.constantize "Moysklad::Entities::#{type.to_s}"
79
- end
80
-
81
76
  private
82
77
 
83
78
  attr_reader :client
84
79
 
85
- def prepare_resource resource
86
- if resource.is_a? Moysklad::Entities::Base
87
- resource.to_xml.to_s
88
- else
89
- resource.to_s
90
- end
91
- end
92
-
93
- def parse content
94
- self.class.entity_class.parse parse_content content
95
- end
96
-
97
- def parse_content content
98
- Nokogiri::XML content
80
+ def parse_get data
81
+ entity_class.build data, self
99
82
  end
100
83
 
101
- def parse_page content
102
- col = Moysklad::Entities::Collection.parse parse_content content
103
-
104
- # TODO Парсится два раза. Оптимизировать. Например сделать динамические CollectionFeature
105
- # и парсить через них
106
-
107
- items = parse content
108
- Moysklad::Entities::Page.new items, col.total, col.start, col.count
84
+ def load_collection data
85
+ collection_class.build data, self
109
86
  end
110
87
 
111
88
  def item_path uuid
@@ -117,11 +94,22 @@ class Moysklad::Resources::Base
117
94
  end
118
95
 
119
96
  def list_path
120
- prefix_path + '/list'
97
+ @list_path ||= prefix_path
121
98
  end
122
99
 
123
- def prefix_path
124
- PREFIX_PATH + self.class.type
100
+ def metadata_path
101
+ prefix_path + '/metadata'
102
+ end
103
+
104
+ def collection_class
105
+ Moysklad::Entities::Collection
106
+ end
107
+
108
+ def entity_class
109
+ ActiveSupport::Inflector.constantize "Moysklad::Entities::#{self.class.type.to_s}"
125
110
  end
126
111
 
112
+ def prefix_path
113
+ PREFIX_PATH + self.class.type.downcase
114
+ end
127
115
  end
@@ -0,0 +1,27 @@
1
+ module Moysklad::Resources
2
+ # Элементы словаря
3
+ class CustomEntities < Base
4
+ # custom_entity_meta_id - id словаря, элементы которого хотим получить
5
+ def initialize custom_entity_meta_id: nil, client:, list_path: nil
6
+ @custom_entity_meta_id = custom_entity_meta_id
7
+ super client: client, list_path: list_path
8
+ end
9
+
10
+ # Публичный чтобы был доступен из индекса
11
+ def cache_key
12
+ [list_path, custom_entity_meta_id].join(':')
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :custom_entity_meta_id
18
+
19
+ def item_path
20
+ raise
21
+ end
22
+
23
+ def list_path
24
+ @list_path || (prefix_path + '/' + custom_entity_meta_id.to_s)
25
+ end
26
+ end
27
+ end
@@ -1,18 +1,22 @@
1
1
  module Moysklad::Resources
2
- # https://online.moysklad.ru/exchange/rest/ms/xml/CustomEntityMetadata/list
3
2
  # Список аттрибутов, которые используются как свойства товара
3
+ # https://online.moysklad.ru/api/remap/1.1/entity/companysettings/metadata/
4
+ # https://online.moysklad.ru/api/remap/1.1/entity/variant/metadata/
5
+ # https://online.moysklad.ru/api/remap/1.1/entity/product/metadata/
4
6
  class CustomEntityMetadata < Base
5
- def self.entity_class
6
- Moysklad::Entities::CustomEntityMetadata
7
- end
8
7
 
9
- def self.type
10
- 'CustomEntityMetadata'
8
+ def list
9
+ raise
11
10
  end
12
11
 
13
- def self.pluralized_type
14
- :custom_entity_metadata
12
+ private
13
+
14
+ def prefix_path
15
+ 'entity/companysettings/metadata/customEntities/'
15
16
  end
16
17
 
18
+ def list_path
19
+ raise 'Список напрямую получить не возможно'
20
+ end
17
21
  end
18
22
  end
@@ -15,6 +15,5 @@ module Moysklad::Resources
15
15
  def self.indexed *args
16
16
  Moysklad::Resources::EmbeddedEntityMetadataIndexed.new new(*args)
17
17
  end
18
-
19
18
  end
20
19
  end
@@ -1,30 +1,39 @@
1
1
  require_relative 'where_filter'
2
+ require_relative 'load_all'
3
+ require_relative 'indexed_cache'
2
4
 
3
5
  module Moysklad::Resources
4
6
  class Indexed < SimpleDelegator
7
+ WrongEntriesCountError = Class.new StandardError
8
+ NoIdInEntity = Class.new StandardError
9
+
5
10
  include WhereFilter
11
+ include LoadAll
12
+ include IndexedCache
6
13
 
7
14
  def initialize resource
8
- raise 'resource должен быть Moysklad::Resources::Base' unless resource.is_a? Moysklad::Resources::Base
15
+ raise TypeError, 'resource должен быть Moysklad::Resources::Base' unless resource.is_a? Moysklad::Resources::Base
9
16
  super resource
10
17
  end
11
18
 
12
19
  # Автоматически подгружает постранично данныез из API и возвращает их все сразу.
13
20
  #
14
21
  # @return [Array of Moysklad::Entities::Base]
15
- def all
16
- @cached_list || pull_list
22
+ def all(params = {})
23
+ cache_fetch do
24
+ pull_list(params)
25
+ end
17
26
  end
18
27
 
19
28
  # Возвращает запрашивемую запись из кеша.
20
29
  # Предварительно подгружает все записи через метод `all`
21
30
  #
22
31
  # @return Moyskald::Entities::Base
23
- def find uuid
24
- index[uuid]
32
+ def find id
33
+ index[id]
25
34
  end
26
35
 
27
- # Перечень uuid-ов всех элементов в ресуресе
36
+ # Перечень id-ов всех элементов в ресуресе
28
37
  #
29
38
  # @return [Array of uuids]
30
39
  def uuids
@@ -45,42 +54,21 @@ module Moysklad::Resources
45
54
  end
46
55
 
47
56
  def index
48
- pull_list unless @_index
49
- @_index
57
+ pull_list unless cached_index
58
+ cached_index
50
59
  end
51
60
 
52
- def pull_list
53
- @cached_list = load_full_list
54
- @_index = prepare_index @cached_list
55
- @cached_list
61
+ def pull_list(params)
62
+ load_all(params)
56
63
  end
57
64
 
58
- def load_full_list
59
- start = 0
60
- list = []
61
-
62
- _page = nil
63
-
64
- begin
65
- _page = page start: start
66
- list += _page.items
67
- break if _page.items.empty?
68
- start = list.count
69
- end while start<_page.total
70
-
71
- raise "При загрузке коллекции в результате колиество не совпадает с total: #{list.count}<>#{_page.total}" unless list.count==_page.total
72
-
73
- list
74
- end
75
-
76
- def prepare_index cached_list
65
+ def prepare_index list
77
66
  i={}
78
- cached_list.each do |r|
79
- raise "У объекта нет uuid: #{r.to_xml}" unless r.respond_to?(:uuid) && r.uuid
80
- i[r.uuid]=r
67
+ list.each do |r|
68
+ raise NoIdInEntity, "У объекта нет id: #{r}" unless r.respond_to?(:id) && r.id
69
+ i[r.id]=r
81
70
  end
82
71
  return i
83
72
  end
84
-
85
73
  end
86
74
  end