moysklad 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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