magentwo 0.1.4 → 0.1.9

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