magento 0.2.0 → 0.3.7

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.
@@ -1,18 +1,13 @@
1
- module Magento
2
- class Customer < Model
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
10
-
11
- def find_by_token(token)
12
- user_request = Request.new(token: token)
13
- customer_hash = user_request.get('customers/me').parse
14
- map_hash Customer, customer_hash
15
- end
16
- end
17
- end
18
- end
1
+ module Magento
2
+ class Customer < Model
3
+ class << self
4
+ alias_method :find_by_id, :find
5
+
6
+ def find_by_token(token)
7
+ user_request = Request.new(token: token)
8
+ customer_hash = user_request.get('customers/me').parse
9
+ ModelMapper.from_hash(customer_hash).to_model(Customer)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,47 +1,79 @@
1
- # frozen_string_literal: true
2
-
3
- require 'dry/inflector'
4
-
5
- module Magento
6
- class Model
7
- class << self
8
- protected
9
-
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
36
- end
37
-
38
- def inflector
39
- @inflector ||= Dry::Inflector.new
40
- end
41
-
42
- def request
43
- @request ||= Request.new
44
- end
45
- end
46
- end
47
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Magento
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
+
23
+ class << self
24
+ extend Forwardable
25
+
26
+ def_delegators :query, :all, :page, :per, :order, :select, :where
27
+
28
+ def find(id)
29
+ hash = request.get("#{api_resource}/#{id}").parse
30
+ ModelMapper.from_hash(hash).to_model(self)
31
+ end
32
+
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}").status.success?
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)
68
+ end
69
+
70
+ def request
71
+ @request ||= Request.new
72
+ end
73
+
74
+ def inflector
75
+ @inflector ||= Dry::Inflector.new
76
+ end
77
+ end
78
+ end
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,9 @@
1
- module Magento
2
- class Product < Model
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
8
- end
9
- end
10
- end
1
+ module Magento
2
+ class Product < Model
3
+ self.primary_key = :sku
4
+
5
+ class << self
6
+ alias_method :find_by_sku, :find
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,150 @@
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
+ value = parse_value_filter(condition, value)
42
+ filters << { field: field, conditionType: condition, value: value }
43
+ end
44
+ filter_groups << { filters: filters }
45
+ self
46
+ end
47
+
48
+ def page(current_page)
49
+ self.current_page = current_page
50
+ self
51
+ end
52
+
53
+ def per(page_size)
54
+ self.page_size = page_size
55
+ self
56
+ end
57
+
58
+ def select(*fields)
59
+ fields = fields.map { |field| parse_field(field) }
60
+ self.fields = "items[#{fields.join(',')}]"
61
+ self
62
+ end
63
+
64
+ def order(attributes)
65
+ if attributes.is_a?(String)
66
+ self.sort_orders = [{ field: verify_id(attributes), direction: :asc }]
67
+ elsif attributes.is_a?(Hash)
68
+ self.sort_orders = []
69
+ attributes.each do |field, direction|
70
+ raise "Invalid sort order direction '#{direction}'" unless %w[asc desc].include?(direction.to_s)
71
+
72
+ sort_orders << { field: verify_id(field), direction: direction }
73
+ end
74
+ end
75
+ self
76
+ end
77
+
78
+ def all
79
+ items = request.get("#{endpoint}?#{query_params}").parse['items']
80
+ items ? items.map { |i| ModelMapper.from_hash(i).to_model(model) } : []
81
+ end
82
+
83
+ private
84
+
85
+ attr_accessor :current_page, :filter_groups, :page_size, :request, :sort_orders, :model, :fields
86
+
87
+ def endpoint
88
+ model.api_resource
89
+ end
90
+
91
+ def verify_id(field)
92
+ return model.primary_key if (field.to_s == 'id') && (field.to_s != model.primary_key.to_s)
93
+
94
+ field
95
+ end
96
+
97
+ def query_params
98
+ query = {
99
+ searchCriteria: {
100
+ filterGroups: filter_groups,
101
+ currentPage: current_page,
102
+ sortOrders: sort_orders,
103
+ pageSize: page_size
104
+ }.compact,
105
+ fields: fields
106
+ }.compact
107
+
108
+ encode query
109
+ end
110
+
111
+ def parse_filter(key)
112
+ patter = /(.*)_([a-z]+)$/
113
+ raise 'Invalid format' unless key.match(patter)
114
+ raise 'Condition not accepted' unless ACCEPTED_CONDITIONS.include?(key.match(patter)[2])
115
+
116
+ key.match(patter).to_a[1..2]
117
+ end
118
+
119
+ def parse_value_filter(condition, value)
120
+ if ['in', 'nin'].include?(condition) && value.is_a?(Array)
121
+ value = value.join(',')
122
+ end
123
+
124
+ value
125
+ end
126
+
127
+ def parse_field(value)
128
+ return verify_id(value) unless value.is_a? Hash
129
+
130
+ value.map do |k, v|
131
+ fields = v.is_a?(Array) ? v.map { |field| parse_field(field) } : [parse_field(v)]
132
+ "#{k}[#{fields.join(',')}]"
133
+ end.join(',')
134
+ end
135
+
136
+ def encode(value, key = nil)
137
+ case value
138
+ when Hash then value.map { |k, v| encode(v, append_key(key, k)) }.join('&')
139
+ when Array then value.each_with_index.map { |v, i| encode(v, "#{key}[#{i}]") }.join('&')
140
+ when nil then ''
141
+ else
142
+ "#{key}=#{CGI.escape(value.to_s)}"
143
+ end
144
+ end
145
+
146
+ def append_key(root_key, key)
147
+ root_key.nil? ? key : "#{root_key}[#{key}]"
148
+ end
149
+ end
150
+ end
@@ -1,103 +1,108 @@
1
- # frozen_string_literal: true
2
-
3
- require 'uri'
4
- require 'http'
5
-
6
- module Magento
7
- class Request
8
- attr_reader :token, :store
9
-
10
- def initialize(token: Magento.token, store: Magento.store)
11
- @token = token
12
- @store = store
13
- end
14
-
15
- def get(resource, token: nil)
16
- save_request(:get, url(resource))
17
- handle_error http_auth.get(url(resource))
18
- end
19
-
20
- def put(resource, body)
21
- save_request(:put, url(resource), body)
22
- handle_error http_auth.put(url(resource), json: body)
23
- end
24
-
25
- def post(resource, body = nil, url_completa = false)
26
- url = url_completa ? resource : url(resource)
27
- save_request(:post, url, body)
28
- handle_error http_auth.post(url, json: body)
29
- end
30
-
31
- private
32
-
33
- def http_auth
34
- HTTP.auth("Bearer #{token}")
35
- end
36
-
37
- def base_url
38
- url = Magento.url.to_s.sub(%r{/$}, '')
39
- "#{url}/rest/#{store}/V1"
40
- end
41
-
42
- def url(resource)
43
- "#{base_url}/#{resource}"
44
- end
45
-
46
- def search_params(field:, value:, conditionType: :eq)
47
- create_params(
48
- filter_groups: {
49
- '0': {
50
- filters: {
51
- '0': {
52
- field: field,
53
- conditionType: conditionType,
54
- value: value
55
- }
56
- }
57
- }
58
- }
59
- )
60
- end
61
-
62
- def field_params(fields:)
63
- create_params(fields: fields)
64
- end
65
-
66
- def create_params(filter_groups: nil, fields: nil, current_page: 1)
67
- CGI.unescape(
68
- {
69
- searchCriteria: {
70
- currentPage: current_page,
71
- filterGroups: filter_groups
72
- }.compact,
73
- fields: fields
74
- }.compact.to_query
75
- )
76
- end
77
-
78
- def handle_error(resp)
79
- return resp if resp.status.success?
80
-
81
- begin
82
- msg = resp.parse['message']
83
- errors = resp.parse['errors']
84
- rescue StandardError
85
- msg = 'Failed access to the magento server'
86
- errors = []
87
- end
88
-
89
- raise Magento::NotFound.new(msg, resp.status.code, errors, @request) if resp.status.not_found?
90
-
91
- raise Magento::MagentoError.new(msg, resp.status.code, errors, @request)
92
- end
93
-
94
- def save_request(method, url, body = nil)
95
- begin
96
- body = body[:product].reject { |e| e == :media_gallery_entries }
97
- rescue StandardError
98
- end
99
-
100
- @request = { method: method, url: url, body: body }
101
- end
102
- end
103
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'http'
5
+
6
+ module Magento
7
+ class Request
8
+ attr_reader :token, :store
9
+
10
+ def initialize(token: Magento.token, store: Magento.store)
11
+ @token = token
12
+ @store = store
13
+ end
14
+
15
+ def get(resource)
16
+ save_request(:get, url(resource))
17
+ handle_error http_auth.get(url(resource))
18
+ end
19
+
20
+ def put(resource, body)
21
+ save_request(:put, url(resource), body)
22
+ handle_error http_auth.put(url(resource), json: body)
23
+ end
24
+
25
+ def post(resource, body = nil, url_completa = false)
26
+ url = url_completa ? resource : url(resource)
27
+ save_request(:post, url, body)
28
+ handle_error http_auth.post(url, json: body)
29
+ end
30
+
31
+ def delete(resource)
32
+ save_request(:delete, url(resource))
33
+ handle_error http_auth.delete(url(resource))
34
+ end
35
+
36
+ private
37
+
38
+ def http_auth
39
+ HTTP.auth("Bearer #{token}")
40
+ end
41
+
42
+ def base_url
43
+ url = Magento.url.to_s.sub(%r{/$}, '')
44
+ "#{url}/rest/#{store}/V1"
45
+ end
46
+
47
+ def url(resource)
48
+ "#{base_url}/#{resource}"
49
+ end
50
+
51
+ def search_params(field:, value:, conditionType: :eq)
52
+ create_params(
53
+ filter_groups: {
54
+ '0': {
55
+ filters: {
56
+ '0': {
57
+ field: field,
58
+ conditionType: conditionType,
59
+ value: value
60
+ }
61
+ }
62
+ }
63
+ }
64
+ )
65
+ end
66
+
67
+ def field_params(fields:)
68
+ create_params(fields: fields)
69
+ end
70
+
71
+ def create_params(filter_groups: nil, fields: nil, current_page: 1)
72
+ CGI.unescape(
73
+ {
74
+ searchCriteria: {
75
+ currentPage: current_page,
76
+ filterGroups: filter_groups
77
+ }.compact,
78
+ fields: fields
79
+ }.compact.to_query
80
+ )
81
+ end
82
+
83
+ def handle_error(resp)
84
+ return resp if resp.status.success?
85
+
86
+ begin
87
+ msg = resp.parse['message']
88
+ errors = resp.parse['errors']
89
+ rescue StandardError
90
+ msg = 'Failed access to the magento server'
91
+ errors = []
92
+ end
93
+
94
+ raise Magento::NotFound.new(msg, resp.status.code, errors, @request) if resp.status.not_found?
95
+
96
+ raise Magento::MagentoError.new(msg, resp.status.code, errors, @request)
97
+ end
98
+
99
+ def save_request(method, url, body = nil)
100
+ begin
101
+ body = body[:product].reject { |e| e == :media_gallery_entries }
102
+ rescue StandardError
103
+ end
104
+
105
+ @request = { method: method, url: url, body: body }
106
+ end
107
+ end
108
+ end