magentwo 0.1.4 → 0.1.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3a841b7d66c45e36a63b99466fd49e7bedfd056f9077e2cdf2e93dd0b7bf9d1
4
- data.tar.gz: 46906bc86d4c0da2517334e916e61b0a647d181587324be4a8f5f5058ae3079e
3
+ metadata.gz: 20edcef61f1dd6dcb2d941e61c8c2ec307b3b34f5a8cc20a6bd4b7e5ac13fb78
4
+ data.tar.gz: 69d77fdbd17a9379a6f17427a3e2095b30aa8f4d36e8f4dc0cba6400767439e0
5
5
  SHA512:
6
- metadata.gz: aa0c925bd64c60d046266bfed1a8f0c6c1c50ab9f69e2f2b5e5fb6700a5fef715db656a11c65c065f4fae273ba994422c9ec810c3903ffdb671d1d723a9242c0
7
- data.tar.gz: 2a49d67d5c11fb054d23cc0d2ac24cb87d813c0704111dadeb75cf7a80626139f579f653ae86d7e61789debe02ef2c5951d178bfac0604b121ebfda4e77b236d
6
+ metadata.gz: e0e08d0b6d433b7e3c8a67a0c1e31a1e15784facf810c3f959cf4c078feb38f3dfde82bc84d55cb3f8ee1fb815b2c87fcfb8273b2ec6bad2598a8f8683c6c2c3
7
+ data.tar.gz: 6068da51a75fa3cf357354341d9c8a8b27976321454ae44dc0a6e7294db97b57e737cc5f4dedb05f81691f587f33630cabe71265ae3c794e98687147a12839e0
data/.gitignore CHANGED
@@ -50,3 +50,5 @@ build-iPhoneSimulator/
50
50
 
51
51
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
52
52
  .rvmrc
53
+
54
+ /cplus
data/README.md CHANGED
@@ -1,4 +1,188 @@
1
- # magentwo
2
- Simple Ruby-Wrapper for the Magento 2 REST API
1
+ This gem is under developement and nowhere near finished but feel free to play around with it.
2
+ I am grateful for any ideas and suggestions
3
3
 
4
- under developement
4
+ # Magentwo
5
+
6
+ Ruby-Wrapper for the Magento 2 REST API
7
+
8
+ # How to install
9
+
10
+ To install the Gem directly use
11
+
12
+ ```
13
+ gem install magentwo
14
+ ```
15
+
16
+ or add the following line to your Gemfile
17
+
18
+ ```
19
+ gem 'magentwo'
20
+ ```
21
+
22
+ and call bundler
23
+
24
+ ```
25
+ bundle
26
+ ```
27
+
28
+ # How to connect to your magento 2 shop
29
+
30
+ When only using one connection simply type
31
+
32
+ ```
33
+ Magentwo.connect "http://example.com", "user_name", "password"
34
+ ```
35
+
36
+ or
37
+
38
+ ```
39
+ Magentwo.connect_with_token "http://example.com", "my_secret_token"
40
+ ```
41
+
42
+ When using multiple connections at once you can save the result of `Magentwo.connect` and use the `Magentwo.with` method
43
+
44
+ ```
45
+ connection1 = Magentwo.connect "http://example1.com", "user_name", "password"
46
+ connection2 = Magentwo.connect_with_token "http://example2.com", "my_secret_token"
47
+
48
+ Magentwo.with (connection1) do
49
+ #do things in the context of connection1
50
+ end
51
+ Magentwo.with (connection2) do
52
+ #do things in the context of connection2
53
+ end
54
+ ```
55
+
56
+ # How to use
57
+
58
+ In Magentwo you interact with the API using Models. These are named according the the REST-API specifications of Magento 2
59
+ The basic functionality is the same for all Models. For products some simple requests would look like this
60
+
61
+ ```
62
+ Magentwo::Product.all #fetches all Products
63
+ Magentwo::Product.first #fetches the first product
64
+ Magentwo::Product.count #returns the number of available products
65
+ Magentwo::Product.fields #returns an array of productfields
66
+ ```
67
+
68
+ # Filtering
69
+
70
+ You can filter requests to search for specific elements
71
+ Here are some examples
72
+
73
+ Look for all customers whose firstname is Foobar
74
+
75
+ ```
76
+ Magentwo::Customer.filter(:firstname => "Foobar").all
77
+ ```
78
+
79
+ Look for all customers whose id is not 42
80
+
81
+ ```
82
+ Magentwo::Customer.exclude(:id => 42).all
83
+ ```
84
+
85
+ You can also combine these
86
+
87
+ ```
88
+ Magentwo::Customer.filter(:firstname => "Foobar").exclude(:id => 42).all
89
+ ```
90
+
91
+ The `filter` and `exclude` methods can also be used to filter for a set. To Request all Customers whose firstname is either Foo or Bar you could write
92
+
93
+ ```
94
+ Magentwo::Customer.filter(:firstname => ["Foo", "bar"]).all
95
+ ```
96
+
97
+ Look for all Products whose name includes the word "Computer"
98
+
99
+ ```
100
+ Magentwo::Product.like(:name => "%Computer%").all
101
+ ```
102
+
103
+ Compare using `gt`, `gteq`, `lt` or `lteq`. These methods do not seem to work with dates, please use `from` and `to` when e.g. trying to fetch all Products that changed within a certain period.
104
+
105
+ ```
106
+ Magentwo::Product.lt(:price => 42).all
107
+ Magentwo::Product.gt(:id => 1337).first
108
+ ```
109
+
110
+ Compare using `from` and `to`, you may also use both to specify a range.
111
+
112
+ ```
113
+ Magentwo::Product.from(:updated_at => Time.new(2019, 1, 1).all
114
+ Magentwo::Product.to(:created_at => Time.new(2019, 2, 1).all
115
+ ```
116
+
117
+ All of these filter-functions can be chained as needed
118
+
119
+ # Select
120
+
121
+ If you know which fields you are interested in you can speed up the fetching process by only requesting these fields
122
+
123
+ ```
124
+ Magentwo::Product.filter(...).select(:id, :sku).all
125
+ ```
126
+
127
+ # Pagination
128
+
129
+ On default the pagesize is set to 20, you can change this with
130
+
131
+ ```
132
+ Magentwo.default_page_size=42
133
+ ```
134
+
135
+ The pagesize can also be set on the fly
136
+ To request page 2 with a pagesize of 100 simply write the following. The second paramter is optional
137
+
138
+ ```
139
+ Magentwo::Product.exclude(:name => "foobar").page(2, 100).all
140
+ ```
141
+
142
+ To iterate threw all the pages use `each_page`. Again the pagesize parameter is optional
143
+
144
+ ```
145
+ Magentwo::Product.each_page(512) do |page|
146
+ p page
147
+ end
148
+ ```
149
+
150
+ You may also want to fetch all pages of products that match a certain criteria
151
+
152
+ ```
153
+ Magentwo::Product.from(:updated_at => my_last_sync_value).each_page(512) do |page|
154
+ p page
155
+ end
156
+ ```
157
+
158
+ # Order
159
+
160
+ By default the results are ordered as Magento2 "thinks" its best. At any place you may add the `order_by` to sepcify this to your liking. If you skip the `ASC/DESC` argument, `ASC` will be set.
161
+
162
+ ```
163
+ Magentwo::Product.order_by(:id, "ASC").all
164
+ Magentwo::Product.order_by(:id, "DESC").all
165
+ ```
166
+
167
+ # Updates
168
+
169
+ To update Models back to Magento 2 use the `save` method
170
+ This switches the first and last name of the Customer Foo Bar
171
+
172
+ ```
173
+ customer = Magentwo::Customer.filter(:first_name => "Foo", :last_name => "Bar").first
174
+ customer.firstname = "Bar"
175
+ customer.lastname = "Foo"
176
+ customer.save
177
+ ```
178
+
179
+ # Delete
180
+
181
+ To delete a Model use the `delete` method
182
+
183
+ ```
184
+ product = Magentwo::Product.first
185
+ product.delete
186
+ ```
187
+
188
+ to be continued ...
data/lib/adapter.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module Magentwo
2
2
  class Adapter < Magentwo::Connection
3
- DateFields = %i(created_at dob updated_at)
3
+ DateTimeFields = %i(created_at updated_at change_status_at)
4
+ DateFields = %i(dob)
4
5
  def call method, path, params
5
6
  http_method, params = case method
6
7
  when :put, :post, :delete then [method, params.to_json]
@@ -10,18 +11,21 @@ module Magentwo
10
11
  end
11
12
 
12
13
  response = self.send(http_method, path, params)
14
+ Magentwo.logger.debug "Response body: #{response.body}" unless response.is_a? TrueClass
13
15
 
14
16
  parsed_response = case method
15
- when :get_with_meta_data, :put, :post, :delete then transform( parse( response))
17
+ when :get_with_meta_data, :put, :post then transform( parse( response))
16
18
  when :get
17
19
  parsed = parse(response)
18
- if parsed[:items]
19
- parsed[:items].map do |item|
20
+ if parsed.is_a?(Hash) && (parsed.has_key? :items)
21
+ (parsed[:items] || []).map do |item|
20
22
  transform item
21
23
  end
22
24
  else
23
25
  transform parsed
24
26
  end
27
+ when :delete
28
+ response
25
29
  else
26
30
  raise ArgumentError, "unknown method type. Expected :get, :get_with_meta_data, :post, :put or :delete. #{method} #{path}"
27
31
  end
@@ -33,18 +37,25 @@ module Magentwo
33
37
  when "200"
34
38
  JSON.parse response.body, :symbolize_names => true
35
39
  else
36
- puts "request failed #{response.code} #{response.body}"
40
+ puts "error #{response.code}: #{JSON.parse(response.body)}"
41
+ return nil
37
42
  end
38
43
  end
39
44
 
40
45
  def transform item
41
- date_transform item if item
46
+ if(item && item.is_a?(Hash))
47
+ date_transform item
48
+ else
49
+ item
50
+ end
42
51
  end
43
52
 
44
53
  def date_transform item
45
- p "datetransform: #{item}"
46
54
  DateFields.each do |date_field|
47
- item[date_field] = Time.new item[date_field] if item[date_field]
55
+ item[date_field] = Date.parse item[date_field] if item[date_field]
56
+ end
57
+ DateTimeFields.each do |datetime_field|
58
+ item[datetime_field] = (Time.parse "#{item[datetime_field]} UTC").getlocal if item[datetime_field]
48
59
  end
49
60
  item
50
61
  end
data/lib/connection.rb CHANGED
@@ -1,44 +1,58 @@
1
1
  module Magentwo
2
2
  class Connection
3
- attr_accessor :host, :port, :user, :password, :token, :base_path
3
+ attr_accessor :host, :port, :user, :password, :token, :base_path, :scheme
4
4
 
5
- def initialize host, user, password, base_path:nil
6
- if host.include? ":"
7
- @host = host.split(":").first
8
- @port = host.split(":").last.to_i
5
+ def initialize uri:, user:nil, password:nil, base_path:nil, token:nil
6
+ uri = URI(uri)
7
+ @host = uri.host
8
+ @port = uri.port
9
+ @scheme = uri.scheme
10
+ @base_path = base_path || "/rest/V1"
11
+
12
+ if (user && password)
13
+ @user = user
14
+ @password = password
15
+ request_token
16
+ elsif (token)
17
+ @token = token
9
18
  else
10
- @host = host
11
- @port = 80
19
+ raise ArgumentError, "expected user/password or token"
12
20
  end
13
- @user = user
14
- @password = password
15
- @base_path = base_path || "/rest/default/V1"
16
- request_token
21
+
17
22
  end
18
23
 
19
24
  def request_token
20
- Net::HTTP.start(self.host,self.port) do |http|
21
- req = Net::HTTP::Post.new("#{base_path}/integration/admin/token")
25
+ Net::HTTP.start(self.host,self.port, :use_ssl => self.scheme == 'https') do |http|
26
+ url = "#{base_path}/integration/admin/token"
27
+ Magentwo.logger.info "POST #{url}"
28
+ req = Net::HTTP::Post.new(url)
22
29
  req.body = {:username=> self.user, :password=> self.password}.to_json
23
30
  req['Content-Type'] = "application/json"
24
31
  req['Content-Length'] = req.body.length
25
- @token = JSON.parse http.request(req).body
32
+ response = http.request(req).body
33
+ @token = JSON.parse response
26
34
  end
27
35
  end
28
36
 
29
37
  def delete path, data
30
- Magentwo.logger.info "DELETE #{path}"
38
+ Magentwo.logger.info "DELETE #{host}/#{base_path}/#{path}"
31
39
  Magentwo.logger.debug "DATA #{data}"
32
40
 
33
- Magentwo.logger.warn "not implemented"
34
-
41
+ url = "#{base_path}/#{path}"
42
+ Net::HTTP.start(self.host,self.port, :use_ssl => self.scheme == 'https') do |http|
43
+ req = Net::HTTP::Delete.new(url)
44
+ req["Authorization"] = "Bearer #{self.token}"
45
+ req['Content-Type'] = "application/json"
46
+ req.body = data
47
+ http.request(req)
48
+ end
35
49
  end
36
50
 
37
51
  def put path, data
38
52
  Magentwo.logger.info "PUT #{host}/#{base_path}/#{path}"
39
53
  Magentwo.logger.debug "DATA #{data}"
40
54
  url = "#{base_path}/#{path}"
41
- Net::HTTP.start(self.host,self.port) do |http|
55
+ Net::HTTP.start(self.host,self.port, :use_ssl => self.scheme == 'https') do |http|
42
56
  req = Net::HTTP::Put.new(url)
43
57
  req["Authorization"] = "Bearer #{self.token}"
44
58
  req['Content-Type'] = "application/json"
@@ -51,7 +65,7 @@ module Magentwo
51
65
  Magentwo.logger.info "POST #{host}/#{path}"
52
66
  Magentwo.logger.debug "DATA #{data}"
53
67
  url = "#{base_path}/#{path}"
54
- Net::HTTP.start(self.host,self.port) do |http|
68
+ Net::HTTP.start(self.host,self.port, :use_ssl => self.scheme == 'https') do |http|
55
69
  req = Net::HTTP::Post.new(url)
56
70
  req["Authorization"] = "Bearer #{self.token}"
57
71
  req['Content-Type'] = "application/json"
@@ -64,7 +78,7 @@ module Magentwo
64
78
  def get path, query
65
79
  Magentwo.logger.info "GET #{host}#{base_path}/#{path}?#{query}"
66
80
  url = "#{base_path}/#{path}?#{query}"
67
- Net::HTTP.start(self.host,self.port) do |http|
81
+ Net::HTTP.start(self.host,self.port, :use_ssl => self.scheme == 'https') do |http|
68
82
  req = Net::HTTP::Get.new(url)
69
83
  req["Authorization"] = "Bearer #{self.token}"
70
84
  req['Content-Type'] = "application/json"
data/lib/dataset.rb CHANGED
@@ -7,7 +7,7 @@ module Magentwo
7
7
  :filters => [],
8
8
  :pagination => {
9
9
  :current_page => Filter::CurrentPage.new(1),
10
- :page_size => Filter::PageSize.new(Magentwo.default_page_size)
10
+ :page_size => Filter::PageSize.new(0)
11
11
  },
12
12
  :ordering => [],
13
13
  :fields => nil
@@ -18,27 +18,44 @@ module Magentwo
18
18
  # Filters
19
19
  ################
20
20
  def filter hash_or_other, invert:false
21
- filter = case hash_or_other
21
+ filters = case hash_or_other
22
22
  when Hash
23
23
  raise ArgumentError, "empty hash supplied" if hash_or_other.empty?
24
- key, value = hash_or_other.first
25
- klass = case value
26
- when Array
27
- invert ? Filter::Nin : Filter::In
28
- else
29
- invert ? Filter::Neq : Filter::Eq
24
+ hash_or_other.map do |key, value|
25
+ klass = case value
26
+ when Array
27
+ invert ? Filter::Nin : Filter::In
28
+ else
29
+ invert ? Filter::Neq : Filter::Eq
30
+ end
31
+ klass.new(key, value)
30
32
  end
31
- klass.new(key, value)
32
33
  else
33
34
  raise ArgumentError, "filter function expects Hash as input"
34
35
  end
35
- Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [filter])
36
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + filters)
36
37
  end
37
38
 
38
39
  def exclude args
39
40
  filter args, invert:true
40
41
  end
41
42
 
43
+ def gt args
44
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::Gt.new(args.keys.first, args.values.first)])
45
+ end
46
+
47
+ def lt args
48
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::Lt.new(args.keys.first, args.values.first)])
49
+ end
50
+
51
+ def gteq args
52
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::Gteq.new(args.keys.first, args.values.first)])
53
+ end
54
+
55
+ def lteq args
56
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::Lteq.new(args.keys.first, args.values.first)])
57
+ end
58
+
42
59
  def select *fields
43
60
  Dataset.new self.model, self.opts.merge(:fields => Filter::Fields.new(fields))
44
61
  end
@@ -47,6 +64,14 @@ module Magentwo
47
64
  Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::Like.new(args.keys.first, args.values.first)])
48
65
  end
49
66
 
67
+ def from args
68
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::From.new(args.keys.first, args.values.first)])
69
+ end
70
+
71
+ def to args
72
+ Dataset.new self.model, self.opts.merge(:filters => self.opts[:filters] + [Filter::To.new(args.keys.first, args.values.first)])
73
+ end
74
+
50
75
  #################
51
76
  # Pagination
52
77
  ################
@@ -84,30 +109,62 @@ module Magentwo
84
109
  self.model.first self
85
110
  end
86
111
 
87
- def all
88
- self.model.all self
112
+ def all meta_data:false
113
+ self.model.all self, :meta_data => meta_data
89
114
  end
90
115
 
91
116
  #################
92
117
  # Transformation
93
118
  ################
119
+ def print_readable
120
+ ds = self
121
+
122
+ puts "*** Pagination ***"
123
+ puts ds.opts[:pagination][:current_page].to_s
124
+ puts ds.opts[:pagination][:page_size].to_s
125
+
126
+ puts "*** Filters ***"
127
+ ds.opts[:filters].each do |filter|
128
+ puts filter.to_s
129
+ end
130
+
131
+ puts "*** Ordering ***"
132
+ order_filters = ds.opts[:ordering]
133
+ if order_filters.size > 0
134
+ order_filters.each do |filter|
135
+ puts filter.to_s
136
+ end
137
+ else
138
+ puts "non specified"
139
+ end
140
+
141
+ puts "*** Fields ***"
142
+ if fields = ds.opts[:fields]&.fields
143
+ puts "Fetch only: #{fields}"
144
+ else
145
+ puts "Fetch everything"
146
+ end
147
+ end
148
+
94
149
  def to_query
150
+ self.validate
151
+ ds = self
95
152
  [
96
- self.opts[:filters]
153
+ ds.opts[:filters]
97
154
  .each_with_index
98
155
  .map { |opt, idx| opt.to_query(idx) }
99
156
  .join("&"),
100
157
 
101
- self.opts[:pagination]
158
+ ds.opts[:pagination]
102
159
  .map { |k, v| v.to_query}
103
160
  .join("&"),
104
161
 
105
162
 
106
- self.opts[:ordering]
163
+ ds.opts[:ordering]
107
164
  .map { |opt, idx| opt.to_query(idx) }
108
165
  .join("&"),
109
166
 
110
- self.opts[:fields]? self.opts[:fields].to_query() : ""
167
+ ds.opts[:fields]? ds.opts[:fields].to_query() : ""
111
168
  ].reject(&:empty?)
112
169
  .join("&")
113
170
  end
@@ -124,5 +181,26 @@ module Magentwo
124
181
  raise ArgumentError, "no block given" unless block_given?
125
182
  self.model.all.each(&block)
126
183
  end
184
+
185
+ def each_page page_size=Magentwo.default_page_size, &block
186
+ raise ArgumentError, "no block given" unless block_given?
187
+
188
+ received_element_count = page_size
189
+ current_page = 1
190
+ total_count = nil
191
+ until(total_count && current_page*page_size > (total_count + page_size)) do
192
+ page = self.page(current_page, page_size).all meta_data:true
193
+ total_count = page[:total_count] unless total_count
194
+ block.call(page[:items])
195
+ current_page += 1
196
+ end
197
+ end
198
+
199
+ #################
200
+ # Validation
201
+ ################
202
+ def validate
203
+ true
204
+ end
127
205
  end
128
206
  end
data/lib/filter.rb CHANGED
@@ -7,23 +7,31 @@ module Magentwo
7
7
  @value = value
8
8
  end
9
9
 
10
- def to_query idx
10
+ def to_query idx, field:self.field, value:self.value
11
11
  [
12
12
  "searchCriteria[filter_groups][#{idx}][filters][0][field]=#{self.field}",
13
- "searchCriteria[filter_groups][#{idx}][filters][0][value]=#{URI::encode(self.value)}",
13
+ "searchCriteria[filter_groups][#{idx}][filters][0][value]=#{URI::encode(self.value.to_s)}",
14
14
  "searchCriteria[filter_groups][#{idx}][filters][0][condition_type]=#{self.class.name.split("::").last.downcase}"]
15
15
  .join("&")
16
16
  end
17
+
18
+ def to_s
19
+ "#{self.field} #{self.class.name.split("::").last.downcase} #{self.value}"
20
+ end
17
21
  end
18
22
 
19
23
  class CompareArray < Compare
20
24
  def to_query idx
21
25
  [
22
26
  "searchCriteria[filter_groups][#{idx}][filters][0][field]=#{self.field}",
23
- "searchCriteria[filter_groups][#{idx}][filters][0][value]=#{URI::encode(self.value.join(","))}",
27
+ "searchCriteria[filter_groups][#{idx}][filters][0][value]=#{URI::encode(self.value.map(&:to_s).join(","))}",
24
28
  "searchCriteria[filter_groups][#{idx}][filters][0][condition_type]=#{self.class.name.split("::").last.downcase}"]
25
29
  .join("&")
26
30
  end
31
+
32
+ def to_s
33
+ "#{self.field} #{self.class.name.split("::").last.downcase} #{self.value}"
34
+ end
27
35
  end
28
36
 
29
37
  class Simple
@@ -36,6 +44,10 @@ module Magentwo
36
44
  def to_query idx=nil
37
45
  "searchCriteria[#{key}]=#{value}"
38
46
  end
47
+
48
+ def to_s
49
+ "#{self.key} == #{self.value}"
50
+ end
39
51
  end
40
52
 
41
53
  class Multi
@@ -49,6 +61,12 @@ module Magentwo
49
61
  "searchCriteria[#{kvp[:key]}]=#{kvp[:value]}"
50
62
  end.join("&")
51
63
  end
64
+
65
+ def to_s
66
+ self.kvps.map do |kvp|
67
+ "#{kvp[:key]} = #{kvp[:value]}"
68
+ end.join("\n")
69
+ end
52
70
  end
53
71
 
54
72
 
@@ -67,6 +85,31 @@ module Magentwo
67
85
  class Like < Magentwo::Filter::Compare
68
86
  end
69
87
 
88
+ class Gt < Magentwo::Filter::Compare
89
+ end
90
+
91
+ class Lt < Magentwo::Filter::Compare
92
+ end
93
+
94
+ class Gteq < Magentwo::Filter::Compare
95
+ end
96
+
97
+ class Lteq < Magentwo::Filter::Compare
98
+ end
99
+
100
+ class From < Magentwo::Filter::Compare
101
+ def to_query idx
102
+ value = case self.value
103
+ when Time then self.value.utc
104
+ else self.value
105
+ end
106
+ super idx, value:value
107
+ end
108
+ end
109
+
110
+ class To < Magentwo::Filter::Compare
111
+ end
112
+
70
113
  class PageSize < Magentwo::Filter::Simple
71
114
  def initialize value
72
115
  super(:page_size, value)
data/lib/magentwo.rb CHANGED
@@ -1,12 +1,36 @@
1
1
  require 'uri'
2
2
  require 'net/http'
3
3
  require 'json'
4
+ require 'time'
4
5
  require 'logger'
5
6
 
6
7
  module Magentwo
7
- Models = %w(base product customer order coupon sales_rule)
8
- def self.connect host, user_name, password
9
- Base.adapter = Adapter.new host, user_name, password
8
+ Models = %w(base product customer order coupon sales_rule category cart stock_item)
9
+ @@mutex = Mutex.new
10
+ def self.connect host=nil, user_name=nil, password=nil
11
+ raise ArgumentError, "no host specified" unless host
12
+ raise ArgumentError, "no user_name specified" unless user_name
13
+ raise ArgumentError, "no password specified" unless password
14
+ Base.adapter = Adapter.new ({uri: host, user: user_name, password: password})
15
+ end
16
+
17
+ def self.connect_with_token host=nil, token=nil
18
+ raise ArgumentError, "no host specified" unless host
19
+ raise ArgumentError, "no token specified" unless token
20
+ Base.adapter = Adapter.new ({token: token, uri: host})
21
+ end
22
+
23
+ def self.with connection
24
+ raise ArgumentError, "no connection specified" unless connection
25
+ @@mutex.synchronize do
26
+ old_connection = Magentwo::Base.adapter
27
+ begin
28
+ Magentwo::Base.adapter = connection
29
+ yield
30
+ ensure
31
+ Magentwo::Base.adapter = old_connection
32
+ end
33
+ end
10
34
  end
11
35
 
12
36
  def self.logger= logger
@@ -14,7 +38,20 @@ module Magentwo
14
38
  end
15
39
 
16
40
  def self.logger
17
- @@logger ||= Logger.new STDOUT, {:level => Logger::DEBUG}
41
+ @@logger ||= Logger.new STDOUT, {:level => Logger::INFO}
42
+ end
43
+
44
+ def self.log_level= level
45
+ new_log_level = case level
46
+ when :debug then Logger::DEBUG
47
+ when :info then Logger::INFO
48
+ when :warn then Logger::WARN
49
+ when :error then Logger::ERROR
50
+ when :fatal then Logger::FATAL
51
+ else
52
+ raise ArgumentError, "invalid log_level"
53
+ end
54
+ self.logger= Logger.new STDOUT, {:level => new_log_level}
18
55
  end
19
56
 
20
57
  def self.default_page_size
@@ -25,7 +62,14 @@ module Magentwo
25
62
  @@default_page_size = page_size
26
63
  end
27
64
 
28
-
65
+ def self.models
66
+ Models.map do |model_file_name|
67
+ model_file_name
68
+ .split('_')
69
+ .map(&:capitalize)
70
+ .join
71
+ end
72
+ end
29
73
  end
30
74
 
31
75
  require_relative 'connection.rb'
@@ -35,5 +79,5 @@ require_relative 'dataset.rb'
35
79
  require_relative 'util/validator.rb'
36
80
 
37
81
  Magentwo::Models.each do |file_name|
38
- require_relative("model/#{file_name}.rb")
82
+ require_relative("model/#{file_name}.rb")
39
83
  end
data/lib/model/base.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  module Magentwo
2
2
  class Base
3
- DatasetMethods = %i(filter exclude select fields count fields info page order_by like)
4
-
5
- attr_accessor :base_path
3
+ DatasetMethods = %i(filter exclude select fields count fields info page order_by like gt lt gteq lteq from to)
6
4
 
7
5
  def initialize args
8
6
  args.each do |key, value|
@@ -20,12 +18,14 @@ module Magentwo
20
18
 
21
19
  def save
22
20
  self.validate
23
- response = Magentwo::Base.call :put, "#{self.class.base_path}/#{self.id}", self
21
+ self.check_presence self.class.unique_identifier
22
+ response = Magentwo::Base.call :put, "#{self.class.base_path}/#{self.send(self.class.unique_identifier)}", self
24
23
  self.class.new response
25
24
  end
26
25
 
27
26
  def delete
28
- Magentwo.logger.warn "not implemented"
27
+ self.check_presence self.class.unique_identifier
28
+ Magentwo::Base.call :delete, "#{self.class.base_path}/#{self.send(self.class.unique_identifier)}", nil
29
29
  end
30
30
 
31
31
  def validate
@@ -64,6 +64,15 @@ module Magentwo
64
64
  class << self
65
65
  attr_accessor :adapter
66
66
 
67
+ def [] unique_identifier_value
68
+ result = Magentwo::Base.get nil, path:"#{base_path}/#{unique_identifier_value}"
69
+ self.new result if result
70
+ end
71
+
72
+ def unique_identifier
73
+ :id
74
+ end
75
+
67
76
  def lower_case_name
68
77
  name = self.name.split(/::/).last
69
78
  "#{name[0,1].downcase}#{name[1..-1]}"
@@ -77,15 +86,36 @@ module Magentwo
77
86
  base_path
78
87
  end
79
88
 
80
- def all ds=self.dataset
81
- self.get(ds.to_query)
89
+ def all ds=self.dataset, meta_data:false
90
+ response = self.get(ds.to_query, :meta_data => meta_data)
91
+ return [] if response.nil?
92
+ items = (meta_data ? response[:items] : response)
82
93
  .map do |item|
83
94
  self.new item
84
95
  end
96
+ if meta_data
97
+ response[:items] = items
98
+ response
99
+ else
100
+ items
101
+ end
85
102
  end
86
103
 
87
104
  def first ds=self.dataset
88
- self.new self.get(ds.page(1, 1).to_query).first
105
+ response = self.get(ds.page(1, 1).to_query).first
106
+ self.new response if response
107
+ end
108
+
109
+ def each_page page_size=Magentwo.default_page_size, &block
110
+ self.dataset.each_page page_size, &block
111
+ end
112
+
113
+ def each &block
114
+ self.dataset.each &block
115
+ end
116
+
117
+ def map &block
118
+ self.dataset.map &block
89
119
  end
90
120
 
91
121
  def dataset
@@ -108,7 +138,7 @@ module Magentwo
108
138
  end
109
139
 
110
140
  def call method, path=self.base_path, params
111
- Magentwo::Base.adapter.call(method, path, params)
141
+ Magentwo::Base.adapter.call(method, path, params)
112
142
  end
113
143
 
114
144
  end
data/lib/model/cart.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Magentwo
2
+ class Cart < Base
3
+ Attributes = %i(id created_at updated_at is_active is_virtual items_count items_qty customer billing_address reserved_order_id orig_order_id currency customer_is_guest customer_note_notify customer_tax_class_id store_id)
4
+ Attributes.each do |attr| attr_accessor attr end
5
+
6
+ class << self
7
+ def get_path
8
+ "#{self.base_path}/search"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Magentwo
2
+ class Category < Base
3
+ #TODO implement
4
+ class << self
5
+ def base_path
6
+ "categories"
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/model/coupon.rb CHANGED
@@ -11,7 +11,7 @@ module Magentwo
11
11
  def generate rule_id, quantity:1, length:16, format:(:alpha), delimiter:"-", delimiter_at_every:4
12
12
  format = format.to_sym
13
13
  Magentwo::Validator.one_of format, :num, :alpha, :alphanum
14
- self.call :post, "coupons/generate",
14
+ self.call :post, "#{base_path}/generate",
15
15
  {
16
16
  :couponSpec => {
17
17
  :rule_id => rule_id,
@@ -23,6 +23,10 @@ module Magentwo
23
23
  }
24
24
  }
25
25
  end
26
+
27
+ def unique_identifier
28
+ :coupon_id
29
+ end
26
30
  end
27
31
 
28
32
  end
data/lib/model/order.rb CHANGED
@@ -1,5 +1,30 @@
1
1
  module Magentwo
2
2
  class Order < Base
3
+ Attributes = %i(base_currency_code base_discount_amount base_discount_invoiced base_grand_total base_discount_tax_compensation_amount base_discount_tax_compensation_invoiced base_shipping_amount base_shipping_discount_amount base_shipping_discount_tax_compensation_amnt base_shipping_incl_tax base_shipping_invoiced base_shipping_tax_amount base_subtotal base_subtotal_incl_tax base_subtotal_invoiced base_tax_amount base_tax_invoiced base_total_due base_total_invoiced base_total_invoiced_cost base_total_paid base_to_global_rate base_to_order_rate billing_address_id created_at customer_dob customer_email customer_firstname customer_gender customer_group_id customer_id customer_is_guest customer_lastname customer_note_notify discount_amount discount_invoiced entity_id global_currency_code grand_total discount_tax_compensation_amount discount_tax_compensation_invoiced increment_id is_virtual order_currency_code protect_code quote_id shipping_amount shipping_description shipping_discount_amount shipping_discount_tax_compensation_amount shipping_incl_tax shipping_invoiced shipping_tax_amount state status store_currency_code store_id store_name store_to_base_rate store_to_order_rate subtotal subtotal_incl_tax subtotal_invoiced tax_amount tax_invoiced total_due total_invoiced total_item_count total_paid total_qty_ordered updated_at weight items billing_address payment status_histories extension_attributes amount_refunded base_amount_refunded base_discount_amount base_discount_invoiced base_discount_tax_compensation_amount base_discount_tax_compensation_invoiced base_original_price base_price base_price_incl_tax base_row_invoiced base_row_total base_row_total_incl_tax base_tax_amount base_tax_invoiced created_at discount_amount discount_invoiced discount_percent free_shipping discount_tax_compensation_amount discount_tax_compensation_invoiced is_qty_decimal item_id name no_discount order_id original_price price price_incl_tax product_id product_type qty_canceled qty_invoiced qty_ordered qty_refunded qty_shipped row_invoiced row_total row_total_incl_tax row_weight sku store_id tax_amount tax_invoiced tax_percent updated_at weight)
4
+ Attributes.each do |attr| attr_accessor attr end
3
5
 
6
+ def products
7
+ product_skus = self.items.map do |item|
8
+ item[:sku]
9
+ end
10
+ Magentwo::Product.filter(:sku => product_skus).all
11
+ end
12
+
13
+ def customer
14
+ self.check_presence :customer_id
15
+ Magentwo::Customer[self.customer_id]
16
+ end
17
+
18
+ class << self
19
+ #this is necessary as the return type of magento2 is not consistent
20
+ def [] unique_identifier
21
+ self.filter(:entity_id => unique_identifier).first
22
+ end
23
+
24
+ def unique_identifier
25
+ Magentwo::Logger.error "orders do not contain id on default requests, therefore they cannot be targeted on the API"
26
+ nil
27
+ end
28
+ end
4
29
  end
5
30
  end
data/lib/model/product.rb CHANGED
@@ -2,5 +2,19 @@ module Magentwo
2
2
  class Product < Base
3
3
  Attributes = %i(id sku name attribute_set_id price status visibility type_id created_at updated_at extension_attributes product_links options media_gallery_entries tier_prices custom_attributes)
4
4
  Attributes.each do |attr| attr_accessor attr end
5
+
6
+ def stocks
7
+ Magentwo::StockItem[self.sku]
8
+ end
9
+
10
+ class << self
11
+ def types
12
+ Magentwo::Base.get nil, path:"#{base_path}/types"
13
+ end
14
+
15
+ def unique_identifier
16
+ :sku
17
+ end
18
+ end
5
19
  end
6
20
  end
@@ -3,10 +3,28 @@ module Magentwo
3
3
  Attributes = %i(rule_id name store_labels description website_ids customer_group_ids uses_per_customer is_active condition action_condition stop_rules_processing is_advanced sort_order simple_action discount_amount discount_step apply_to_shipping times_used is_rss coupon_type use_auto_generation uses_per_coupon simple_free_shipping)
4
4
  Attributes.each do |attr| attr_accessor attr end
5
5
 
6
+ def generate quantity:1, length:16, format:(:alpha), delimiter:"-", delimiter_at_every:4
7
+ self.check_presence :rule_id
8
+ Magentwo::Coupon.generate self.rule_id, quantity:quantity, length:length, format:format, delimiter:delimiter, delimiter_at_every:delimiter_at_every
9
+ end
10
+
11
+ def coupons
12
+ self.check_presence :rule_id
13
+ Magentwo::Coupon.filter(:rule_id => self.rule_id).all
14
+ end
15
+
16
+ def to_json
17
+ Hash["rule", self.to_h].to_json
18
+ end
19
+
6
20
  class << self
7
21
  def get_path
8
22
  "#{base_path}/search"
9
23
  end
24
+
25
+ def unique_identifier
26
+ :rule_id
27
+ end
10
28
  end
11
29
 
12
30
  end
@@ -0,0 +1,12 @@
1
+ # Usage:
2
+ # Magentwo::StockItems['sku']
3
+
4
+ module Magentwo
5
+ class StockItem < Base
6
+ Attributes = %i(item_id product_id stock_id qty is_in_stock is_qty_decimal show_default_notification_message use_config_min_qty min_qty use_config_min_sale_qty min_sale_qty use_config_max_sale_qty max_sale_qty use_config_backorders backorders use_config_notify_stock_qty notify_stock_qty use_config_qty_increments qty_increments use_config_enable_qty_inc enable_qty_increments use_config_manage_stock manage_stock low_stock_date is_decimal_divided stock_status_changed_auto)
7
+ Attributes.each do |attr| attr_accessor attr end
8
+
9
+ class << self
10
+ end
11
+ end
12
+ end
data/magentwo.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'magentwo'
3
- s.version = '0.1.4'
3
+ s.version = '0.1.9'
4
4
  s.date = '2019-01-17'
5
5
  s.summary = "Magento 2 API Wrapper"
6
6
  s.description = "Provides a simple Ruby Interface to interact with the Magento 2 API"
data/spec/dataset_spec.rb CHANGED
@@ -18,9 +18,9 @@ describe Magentwo::Dataset do
18
18
  expect(dataset.opts[:pagination]).to have_key :current_page
19
19
  expect(dataset.opts[:pagination]).to have_key :page_size
20
20
  end
21
- it "requests #{Magentwo::Dataset::DefaultPageSize} items on default" do
21
+ it "requests all items on default" do
22
22
  expect(initial_query).to include "searchCriteria[current_page]=1"
23
- expect(initial_query).to include "searchCriteria[page_size]=#{Magentwo::Dataset::DefaultPageSize}"
23
+ expect(initial_query).to include "searchCriteria[page_size]=0"
24
24
  end
25
25
  end
26
26
 
@@ -37,6 +37,31 @@ describe Magentwo::Dataset do
37
37
  end
38
38
  end
39
39
 
40
+ context "multi filter" do
41
+ let(:multi_filter_ds) {dataset.filter(:name => "foobar").filter(:id => 42)}
42
+ let(:multi_filter_query) {multi_filter_ds.to_query}
43
+ let(:multi_filter_in_one_ds) {dataset.filter(:name => "foobar", :id => 42)}
44
+ let(:multi_filter_in_one_query) {multi_filter_in_one_ds.to_query}
45
+ it "contains filter with type Filter::Eq" do
46
+ expect(multi_filter_ds.opts[:filters]).to include Magentwo::Filter::Eq
47
+ end
48
+ it "contains two filters" do
49
+ expect(multi_filter_ds.opts[:filters].count).to eq 2
50
+ end
51
+ it "compute query" do
52
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][0][filters][0][field]=name"
53
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][0][filters][0][condition_type]=eq"
54
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][0][filters][0][value]=foobar"
55
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][1][filters][0][field]=id"
56
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][1][filters][0][condition_type]=eq"
57
+ expect(multi_filter_query).to include "searchCriteria[filter_groups][1][filters][0][value]=42"
58
+ end
59
+ it "is the same for multiple keys in one filter" do
60
+ expect(multi_filter_ds.opts.count).to eq multi_filter_in_one_ds.opts.count
61
+ expect(multi_filter_query).to eq multi_filter_in_one_query
62
+ end
63
+ end
64
+
40
65
  context "select" do
41
66
  let(:name_select_ds) {dataset.select(:name)}
42
67
  let(:name_select_query) {name_select_ds.to_query}
data/spec/product_spec.rb CHANGED
@@ -1,4 +1,83 @@
1
1
  require_relative '../lib/magentwo.rb'
2
2
 
3
3
  describe Magentwo::Product do
4
+ before(:all) do
5
+ Magentwo.logger = Logger.new STDOUT, {:level => Logger::ERROR}
6
+ @original_count = Magentwo::Product.count
7
+ end
8
+
9
+ context "#dataset" do
10
+ let(:dataset) {Magentwo::Product.dataset}
11
+ it "returns dataset" do
12
+ expect(dataset).to be_a Magentwo::Dataset
13
+ end
14
+ end
15
+
16
+ context "#count" do
17
+ let(:count) {Magentwo::Product.count}
18
+ it "responds to :count" do
19
+ expect(Magentwo::Product).to respond_to :count
20
+ end
21
+ it "correct count" do
22
+ expect(count).to eq @original_count
23
+ end
24
+ it "count is integer" do
25
+ expect(count).to be_a Integer
26
+ end
27
+ end
28
+
29
+ context "#all" do
30
+ let(:products) {Magentwo::Product.all}
31
+ let(:ds) {Magentwo::Product.dataset}
32
+
33
+ it "responds to all" do
34
+ expect(Magentwo::Product).to respond_to :all
35
+ end
36
+ it "returns an array" do
37
+ expect(products).to be_a Array
38
+ end
39
+ it "requested all" do
40
+ expect(products.count).to eq @original_count
41
+ end
42
+ end
43
+
44
+ context "#fields" do
45
+ let(:fields) {Magentwo::Product.fields}
46
+
47
+ it "returns array of symbols" do
48
+ expect(fields).to be_a Array
49
+ fields.each do |field|
50
+ expect(field).to be_a Symbol
51
+ end
52
+ end
53
+ end
54
+
55
+ context "#first" do
56
+ let(:product) {Magentwo::Product.first}
57
+
58
+ it "returns a product" do
59
+ expect(product).to be_a Magentwo::Product
60
+ end
61
+ end
62
+
63
+ context "#types" do
64
+ let(:types) {Magentwo::Product.types}
65
+
66
+ it "returns array" do
67
+ expect(types).to be_a Array
68
+ end
69
+ end
70
+
71
+ context "#[]" do
72
+ let(:first_product) {Magentwo::Product.first}
73
+ let(:by_sku_product) {Magentwo::Product[first_product.sku]}
74
+
75
+ it "returns a product" do
76
+ expect(by_sku_product).to be_a Magentwo::Product
77
+ end
78
+
79
+ it "returns product by :sku" do
80
+ expect(first_product.sku).to eq by_sku_product.sku
81
+ end
82
+ end
4
83
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magentwo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Mueß
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2019-01-17 00:00:00.000000000 Z
@@ -27,11 +27,14 @@ files:
27
27
  - lib/filter.rb
28
28
  - lib/magentwo.rb
29
29
  - lib/model/base.rb
30
+ - lib/model/cart.rb
31
+ - lib/model/category.rb
30
32
  - lib/model/coupon.rb
31
33
  - lib/model/customer.rb
32
34
  - lib/model/order.rb
33
35
  - lib/model/product.rb
34
36
  - lib/model/sales_rule.rb
37
+ - lib/model/stock_item.rb
35
38
  - lib/util/validator.rb
36
39
  - magentwo.gemspec
37
40
  - spec/base_model_spec.rb
@@ -43,7 +46,7 @@ licenses:
43
46
  - MIT
44
47
  metadata:
45
48
  source_code_uri: https://github.com/Arkad82x/magentwo
46
- post_install_message:
49
+ post_install_message:
47
50
  rdoc_options: []
48
51
  require_paths:
49
52
  - lib
@@ -58,8 +61,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
61
  - !ruby/object:Gem::Version
59
62
  version: '0'
60
63
  requirements: []
61
- rubygems_version: 3.0.2
62
- signing_key:
64
+ rubygems_version: 3.2.15
65
+ signing_key:
63
66
  specification_version: 4
64
67
  summary: Magento 2 API Wrapper
65
68
  test_files: []