magento 0.2.0 → 0.3.0

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: d8bc5f8a39bdb839264e76b211f08b5ce3621340c64e866295456ec136180155
4
- data.tar.gz: 4711ecfd3c80b9f52dce500b8d832ebe9dd2f3ef981e9245eb4730bcfc1bc529
3
+ metadata.gz: 78965c7e294c387a88b86cf0af3a099f54729ca292050d1b0cc71046f6e5de6c
4
+ data.tar.gz: 7e714fbb399e0ed27946984437d2a4603481f33e98ffa551e5f83b0987518e9c
5
5
  SHA512:
6
- metadata.gz: c4eeca2012769013e626ffa61689d487ebcf92430cd9a0740254f16bffb2ec11f62b0b8c519446fe314a571a8def6c20e46ce80def22f1ea599ff4350d81c9c3
7
- data.tar.gz: df313171a3767e8bf326fbf6bb45aa53010f1a8b3f7469b4cb27cb44b82ea2e30fa19eeb7165fe3380e8c50c89760c38721cdeeb5d24b3236325da94411a1fb9
6
+ metadata.gz: 36cc52f478ee96696a451b1bf943db80128ca3f333391c628e026305d67d9f242fe699efc7dbbf624707945fdde47cf2f7f87391e24543e8cb4eefe3984d3bd1
7
+ data.tar.gz: 1f0ab0fd15b026b47ed6de9252e249bb084cd92fd60021beafc90e1341ea7439e2a9d75ad5046fce1cd89a6947626ae2f475fe4fa3c8dca5a88c457ba4502d00
data/.gitignore CHANGED
@@ -25,4 +25,4 @@ test/vcr_cassettes
25
25
 
26
26
  .vscode
27
27
  .byebug_history
28
- test.rb
28
+ /*test.rb
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Add in your Gemfile
6
6
 
7
7
  ```rb
8
- gem 'magento', '~> 0.2.0'
8
+ gem 'magento', '~> 0.3.0'
9
9
  ```
10
10
 
11
11
  or run
@@ -22,67 +22,102 @@ Magento.token = 'MAGENTO_API_KEY'
22
22
  Magento.store = :default # optional, Default is :all
23
23
  ```
24
24
 
25
- ## Product
26
-
27
- ### Get product details by sku
28
-
25
+ ## Models
29
26
  ```rb
30
- Magento::Product.find_by_sku('sku-test')
27
+ Magento::Product
28
+ Magento::Order
29
+ Magento::Country
30
+ Magento::Category
31
31
  ```
32
32
 
33
- ## Customer
33
+ ## Get details
34
34
 
35
- ### Get customer by id
36
35
  ```rb
37
- Magento::Customer.find(id) # or
38
- Magento::Customer.find_by_id(id)
36
+ Magento::Product.find('sku-test')
37
+ Magento::Order.find(25)
38
+ Magento::Country.find('BR')
39
39
  ```
40
+ \* _same pattern to all models_
41
+
42
+ **Outside pattern**
43
+
44
+ Get customer by token
40
45
 
41
- ### Get customer by token
42
46
  ```rb
43
47
  Magento::Customer.find_by_token('user_token')
44
48
  ```
45
49
 
46
- ## Countries
47
-
48
- ### Get available regions for a country
50
+ ## Get List
49
51
 
50
52
  ```rb
51
- country = Magento::Country.find('BR')
53
+ Magento::Product.all
54
+ ```
52
55
 
53
- country.available_regions
56
+ #### Select fields:
57
+ ```rb
58
+ Magento::Product.select(:id, :sku, :name).all
59
+ Magento::Product.select(:id, :sku, :name, extension_attributes: :category_links }.all
60
+ Magento::Product.select(:id, :sku, :name, extension_attributes: [:category_links, :website_ids]).all
61
+ Magento::Product.select(:id, :sku, :name, extension_attributes: [:website_ids, { category_links: :category_id }]).all
54
62
  ```
55
63
 
56
- # TODO
57
- ### Get product list
64
+ #### Filters:
58
65
 
59
- Get all
60
66
  ```rb
61
- Magento::Product.all()
67
+ Magento::Product.where(name_like: 'IPhone%').all
68
+ Magento::Product.where(price_gt: 100).all
69
+ Magento::Product.where(price_gt: 100, price_lt: 200).all
62
70
  ```
63
71
 
64
- Set page and quantity per page
72
+ | Condition | Notes |
73
+ | ----------| ------|
74
+ |eq | Equals. |
75
+ |finset | A value within a set of values |
76
+ |from | The beginning of a range. Must be used with to |
77
+ |gt | Greater than |
78
+ |gteq | Greater than or equal |
79
+ |in | In. The value can contain a comma-separated list of values. |
80
+ |like | Like. The value can contain the SQL wildcard characters when like is |specified.
81
+ |lt | Less than |
82
+ |lteq | Less than or equal |
83
+ |moreq | More or equal |
84
+ |neq | Not equal |
85
+ |nfinset | A value that is not within a set of values |
86
+ |nin | Not in. The value can contain a comma-separated list of values. |
87
+ |notnull | Not null |
88
+ |null | Null |
89
+ |to | The end of a range. Must be used with from |
90
+
91
+
92
+ #### SortOrder:
93
+
65
94
  ```rb
66
- Magento::Product.all(page: 1, page_size: 25) # Default page size is 50
95
+ Magento::Product.order(:sku).all
96
+ Magento::Product.order(sku: :desc).all
97
+ Magento::Product.order(status: :desc, name: :asc).all
67
98
  ```
68
99
 
69
- Filter list by attribute
70
- ```rb
71
- Magento::Product.all(name_like: 'IPhone%')
100
+ #### Pagination:
72
101
 
73
- Magento::Product.all(price_gt: 100, page: 2)
102
+ ```rb
103
+ # Set page and quantity per page
104
+ Magento::Product.page(1).per(25) # Default per is 50
74
105
  ```
75
106
 
76
- ### Search products
107
+ #### Example of several options together:
77
108
  ```rb
78
- Magento::Product.search('tshort')
109
+ Magento::Product.select(:sku, :name, :price)
110
+ .where(name_like: 'Tshort%')
111
+ .order(price: :desc)
112
+ .per(10)
113
+ .all
79
114
  ```
80
115
 
81
- ## Order
116
+ \* _same pattern to all models_
117
+ ___
118
+ ## \######### TODO \##########
82
119
 
83
- ### Create Order as admin user
84
-
85
- See the [documentation](https://magento.redoc.ly/2.4-admin/#operation/salesOrderRepositoryV1SavePost) to all attributes
120
+ ## Create
86
121
 
87
122
  ```rb
88
123
  Magento::Order.create(
@@ -109,3 +144,33 @@ Magento::Order.create(
109
144
  }
110
145
  )
111
146
  ```
147
+
148
+ ### Update
149
+
150
+ ```rb
151
+ product = Magento::Product.find('sku-teste')
152
+
153
+ product.name = 'Updated name'
154
+ product.save
155
+
156
+ # or
157
+
158
+ product.update(name: 'Updated name')
159
+ ```
160
+
161
+ ### Delete
162
+
163
+ ```rb
164
+ product = Magento::Product.find('sku-teste')
165
+
166
+ product.delete
167
+
168
+ # or
169
+
170
+ Magento::Product.delete('sku-teste')
171
+ ```
172
+
173
+ ### Search products
174
+ ```rb
175
+ Magento::Product.search('tshort')
176
+ ```
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'time'
4
+ require 'dry/inflector'
4
5
 
5
6
  require_relative 'magento/errors'
6
7
  require_relative 'magento/request'
7
8
  require_relative 'magento/model'
9
+ require_relative 'magento/model_mapper'
10
+ require_relative 'magento/query'
8
11
  require_relative 'magento/product'
9
12
  require_relative 'magento/country'
10
13
  require_relative 'magento/customer'
14
+ require_relative 'magento/order'
11
15
 
12
16
  Dir[File.expand_path('magento/shared/*.rb', __dir__)].map { |f| require f }
13
17
 
@@ -0,0 +1,4 @@
1
+ module Magento
2
+ class Category < Model
3
+ end
4
+ end
@@ -1,10 +1,5 @@
1
1
  module Magento
2
2
  class Country < Model
3
- class << self
4
- def find(code)
5
- country_hash = request.get("directory/countries/#{code}").parse
6
- map_hash Country, country_hash
7
- end
8
- end
3
+ self.endpoint = 'directory/countries'
9
4
  end
10
5
  end
@@ -1,17 +1,12 @@
1
1
  module Magento
2
2
  class Customer < Model
3
3
  class << self
4
- def find_by_id(id)
5
- customer_hash = request.get("customers/#{id}").parse
6
- map_hash Customer, customer_hash
7
- end
8
-
9
- alias_method :find, :find_by_id
4
+ alias_method :find_by_id, :find
10
5
 
11
6
  def find_by_token(token)
12
7
  user_request = Request.new(token: token)
13
8
  customer_hash = user_request.get('customers/me').parse
14
- map_hash Customer, customer_hash
9
+ ModelMapper.from_hash(customer_hash).to_model(Customer)
15
10
  end
16
11
  end
17
12
  end
@@ -1,47 +1,79 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/inflector'
3
+ require 'forwardable'
4
4
 
5
5
  module Magento
6
6
  class Model
7
+ def save
8
+ body = ModelMapper.from_object(self).to_hash
9
+ self.class.update(send(self.class.primary_key), body)
10
+ end
11
+
12
+ def update(attrs)
13
+ raise "#{self.class.name} not saved" if send(self.class.primary_key).nil?
14
+
15
+ attrs.each { |key, value| send("#{key}=", value) }
16
+ save
17
+ end
18
+
19
+ def delete
20
+ self.class.delete(send(self.class.primary_key))
21
+ end
22
+
7
23
  class << self
8
- protected
24
+ extend Forwardable
25
+
26
+ def_delegators :query, :all, :page, :per, :order, :select
9
27
 
10
- def map_hash(klass, values)
11
- object = klass.new
12
- values.each do |key, value|
13
- object.singleton_class.instance_eval { attr_accessor key }
14
- if value.is_a?(Hash)
15
- class_name = inflector.camelize(inflector.singularize(key))
16
- value = map_hash(Object.const_get("Magento::#{class_name}"), value)
17
- elsif value.is_a?(Array)
18
- value = map_array(key, value)
19
- end
20
- object.send("#{key}=", value)
21
- end
22
- object
23
- end
24
-
25
- def map_array(key, values)
26
- result = []
27
- values.each do |value|
28
- if value.is_a?(Hash)
29
- class_name = inflector.camelize(inflector.singularize(key))
30
- result << map_hash(Object.const_get("Magento::#{class_name}"), value)
31
- else
32
- result << value
33
- end
34
- end
35
- result
28
+ def find(id)
29
+ hash = request.get("#{api_resource}/#{id}").parse
30
+ ModelMapper.from_hash(hash).to_model(self)
36
31
  end
37
32
 
38
- def inflector
39
- @inflector ||= Dry::Inflector.new
33
+ def create(attributes)
34
+ body = { entity_name => attributes }
35
+ hash = request.post(api_resource, body).parse
36
+ ModelMapper.from_hash(hash).to_model(self)
37
+ end
38
+
39
+ def delete(id)
40
+ request.delete("#{api_resource}/#{id}")
41
+ end
42
+
43
+ def update(id, attributes)
44
+ body = { entity_name => attributes }
45
+ hash = request.put("#{api_resource}/#{id}", body).parse
46
+ ModelMapper.from_hash(hash).to_model(self)
47
+ end
48
+
49
+ def api_resource
50
+ endpoint || inflector.pluralize(entity_name)
51
+ end
52
+
53
+ def entity_name
54
+ inflector.underscore(name).sub('magento/', '')
55
+ end
56
+
57
+ def primary_key
58
+ @primary_key || :id
59
+ end
60
+
61
+ protected
62
+
63
+ attr_writer :primary_key
64
+ attr_accessor :endpoint
65
+
66
+ def query
67
+ Query.new(self)
40
68
  end
41
69
 
42
70
  def request
43
71
  @request ||= Request.new
44
72
  end
73
+
74
+ def inflector
75
+ @inflector ||= Dry::Inflector.new
76
+ end
45
77
  end
46
78
  end
47
79
  end
@@ -0,0 +1,71 @@
1
+ class ModelMapper
2
+ def initialize(from)
3
+ @from = from
4
+ end
5
+
6
+ def to_model(model)
7
+ map_hash(model, @from)
8
+ end
9
+
10
+ def to_hash
11
+ self.class.to_hash(@from)
12
+ end
13
+
14
+ def self.from_object(object)
15
+ new(object)
16
+ end
17
+
18
+ def self.from_hash(values)
19
+ new(values)
20
+ end
21
+
22
+ def self.to_hash(object)
23
+ hash = {}
24
+ object.instance_variables.each do |attr|
25
+ key = attr.to_s.delete('@')
26
+ value = object.send(key)
27
+ value = to_hash(value) if value.class.name.include?('Magento::')
28
+ if value.is_a? Array
29
+ value = value.map do |item|
30
+ item.class.name.include?('Magento::') ? to_hash(item) : item
31
+ end
32
+ end
33
+ hash[key] = value
34
+ end
35
+ hash
36
+ end
37
+
38
+ private
39
+
40
+ def map_hash(model, values)
41
+ object = model.new
42
+ values.each do |key, value|
43
+ object.singleton_class.instance_eval { attr_accessor key }
44
+ if value.is_a?(Hash)
45
+ class_name = inflector.camelize(inflector.singularize(key))
46
+ value = map_hash(Object.const_get("Magento::#{class_name}"), value)
47
+ elsif value.is_a?(Array)
48
+ value = map_array(key, value)
49
+ end
50
+ object.send("#{key}=", value)
51
+ end
52
+ object
53
+ end
54
+
55
+ def map_array(key, values)
56
+ result = []
57
+ values.each do |value|
58
+ if value.is_a?(Hash)
59
+ class_name = inflector.camelize(inflector.singularize(key))
60
+ result << map_hash(Object.const_get("Magento::#{class_name}"), value)
61
+ else
62
+ result << value
63
+ end
64
+ end
65
+ result
66
+ end
67
+
68
+ def inflector
69
+ @inflector ||= Dry::Inflector.new
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ module Magento
2
+ class Order < Model
3
+ self.primary_key = :entity_id
4
+ end
5
+ end
@@ -1,10 +1,7 @@
1
1
  module Magento
2
2
  class Product < Model
3
3
  class << self
4
- def find_by_sku(sku)
5
- product_hash = request.get("products/#{sku}").parse
6
- map_hash Product, product_hash
7
- end
4
+ alias_method :find_by_sku, :find
8
5
  end
9
6
  end
10
7
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Magento
6
+ class Query
7
+ ACCEPTED_CONDITIONS = [
8
+ 'eq', # Equals.
9
+ 'finset', # A value within a set of values
10
+ 'from', # The beginning of a range. Must be used with to
11
+ 'gt', # Greater than
12
+ 'gteq', # Greater than or equal
13
+ 'in', # In. The value can contain a comma-separated list of values.
14
+ 'like', # Like. The value can contain the SQL wildcard characters when like is specified.
15
+ 'lt', # Less than
16
+ 'lteq', # Less than or equal
17
+ 'moreq', # More or equal
18
+ 'neq', # Not equal
19
+ 'nfinset', # A value that is not within a set of values
20
+ 'nin', # Not in. The value can contain a comma-separated list of values.
21
+ 'notnull', # Not null
22
+ 'null', # Null
23
+ 'to' # The end of a range. Must be used with from
24
+ ].freeze
25
+
26
+ def initialize(model, request: Request.new)
27
+ @model = model
28
+ @request = request
29
+ @filter_groups = nil
30
+ @current_page = 1
31
+ @page_size = 50
32
+ @sort_orders = nil
33
+ @fields = nil
34
+ end
35
+
36
+ def where(attributes)
37
+ self.filter_groups = [] unless filter_groups
38
+ filters = []
39
+ attributes.each do |key, value|
40
+ field, condition = parse_filter(key)
41
+ filters << { field: field, conditionType: condition, value: value }
42
+ end
43
+ filter_groups << { filters: filters }
44
+ self
45
+ end
46
+
47
+ def page(current_page)
48
+ self.current_page = current_page
49
+ self
50
+ end
51
+
52
+ def per(page_size)
53
+ self.page_size = page_size
54
+ self
55
+ end
56
+
57
+ def select(*fields)
58
+ fields = fields.map { |field| parse_field(field) }
59
+ self.fields = "items[#{fields.join(',')}]"
60
+ self
61
+ end
62
+
63
+ def order(attributes)
64
+ if attributes.is_a?(String)
65
+ self.sort_orders = [{ field: verify_id(attributes), direction: :asc }]
66
+ elsif attributes.is_a?(Hash)
67
+ self.sort_orders = []
68
+ attributes.each do |field, direction|
69
+ raise "Invalid sort order direction '#{direction}'" unless %w[asc desc].include?(direction.to_s)
70
+
71
+ sort_orders << { field: verify_id(field), direction: direction }
72
+ end
73
+ end
74
+ self
75
+ end
76
+
77
+ def all
78
+ items = request.get("#{endpoint}?#{query_params}").parse['items']
79
+ items ? items.map { |i| ModelMapper.from_hash(i).to_model(model) } : []
80
+ end
81
+
82
+ private
83
+
84
+ attr_accessor :current_page, :filter_groups, :page_size, :request, :sort_orders, :model, :fields
85
+
86
+ def endpoint
87
+ model.api_resource
88
+ end
89
+
90
+ def verify_id(field)
91
+ return model.primary_key if (field.to_s == 'id') && (field.to_s != model.primary_key.to_s)
92
+
93
+ field
94
+ end
95
+
96
+ def query_params
97
+ query = {
98
+ searchCriteria: {
99
+ filterGroups: filter_groups,
100
+ currentPage: current_page,
101
+ sortOrders: sort_orders,
102
+ pageSize: page_size
103
+ }.compact,
104
+ fields: fields
105
+ }.compact
106
+
107
+ encode query
108
+ end
109
+
110
+ def parse_filter(key)
111
+ patter = /(.*)_([a-z]+)$/
112
+ raise 'Invalid format' unless key.match(patter)
113
+ raise 'Condition not accepted' unless ACCEPTED_CONDITIONS.include?(key.match(patter)[2])
114
+
115
+ key.match(patter).to_a[1..2]
116
+ end
117
+
118
+ def parse_field(value)
119
+ return verify_id(value) unless value.is_a? Hash
120
+
121
+ value.map do |k, v|
122
+ fields = v.is_a?(Array) ? v.map { |field| parse_field(field) } : [parse_field(v)]
123
+ "#{k}[#{fields.join(',')}]"
124
+ end.join(',')
125
+ end
126
+
127
+ def encode(value, key = nil)
128
+ case value
129
+ when Hash then value.map { |k, v| encode(v, append_key(key, k)) }.join('&')
130
+ when Array then value.each_with_index.map { |v, i| encode(v, "#{key}[#{i}]") }.join('&')
131
+ when nil then ''
132
+ else
133
+ "#{key}=#{CGI.escape(value.to_s)}"
134
+ end
135
+ end
136
+
137
+ def append_key(root_key, key)
138
+ root_key.nil? ? key : "#{root_key}[#{key}]"
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class Item; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class Payment; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class PaymentAdditionalInfo; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class Shipping; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class ShippingAssignment; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class Total; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module Magento
2
+ class Value; end
3
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'magento'
5
- s.version = '0.2.0'
5
+ s.version = '0.3.0'
6
6
  s.date = '2020-07-31'
7
7
  s.summary = 'Magento Ruby library'
8
8
  s.description = 'Magento Ruby library'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magento
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wallas Faria
@@ -48,23 +48,34 @@ files:
48
48
  - Gemfile
49
49
  - README.md
50
50
  - lib/magento.rb
51
+ - lib/magento/category.rb
51
52
  - lib/magento/country.rb
52
53
  - lib/magento/customer.rb
53
54
  - lib/magento/errors.rb
54
55
  - lib/magento/model.rb
56
+ - lib/magento/model_mapper.rb
57
+ - lib/magento/order.rb
55
58
  - lib/magento/product.rb
59
+ - lib/magento/query.rb
56
60
  - lib/magento/request.rb
57
61
  - lib/magento/shared/address.rb
58
62
  - lib/magento/shared/available_regions.rb
59
63
  - lib/magento/shared/category_link.rb
60
64
  - lib/magento/shared/custom_attribute.rb
61
65
  - lib/magento/shared/extension_attribute.rb
66
+ - lib/magento/shared/item.rb
62
67
  - lib/magento/shared/media_gallery_entry.rb
63
68
  - lib/magento/shared/option.rb
69
+ - lib/magento/shared/payment.rb
70
+ - lib/magento/shared/payment_additional_info.rb
64
71
  - lib/magento/shared/product_link.rb
65
72
  - lib/magento/shared/region.rb
73
+ - lib/magento/shared/shipping.rb
74
+ - lib/magento/shared/shipping_assignment.rb
66
75
  - lib/magento/shared/stock_item.rb
67
76
  - lib/magento/shared/tier_price.rb
77
+ - lib/magento/shared/total.rb
78
+ - lib/magento/shared/value.rb
68
79
  - magento.gemspec
69
80
  homepage: https://github.com/WallasFaria/magento-ruby
70
81
  licenses: []