market_hub 0.1.0 → 0.23.5

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.
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module Models
5
+ module MercadoLivre
6
+ # Classe que representa uma Variação no Mercado Livre
7
+ class Variation < MarketHub::Models::Base
8
+
9
+ attr_accessor :item_id, :variation_id, :attribute_combinations, :price, :available_quantity, :picture_ids, :catalog_product_id, :attributes
10
+
11
+ validates_presence_of :item_id, :attribute_combinations, :price, :available_quantity, message: 'não pode estar em branco.'
12
+
13
+ def initialize(client, body = {}, options = {})
14
+ super(client, body, options)
15
+ unless body.empty?
16
+ @id = body.dig(:variation_id) || body.dig('id')
17
+ @item_id = body.dig(:item_id) || body.dig('item_id')
18
+ @variation_id = body.dig(:variation_id) || body.dig('id')
19
+ @attribute_combinations = body.dig(:attribute_combinations) || body.dig('attribute_combinations')
20
+ @price = (body.dig(:price) || body.dig('price')).to_f
21
+ @available_quantity = body.dig(:available_quantity) || body.dig('available_quantity')
22
+ @picture_ids = body.dig(:picture_ids) || body.dig('picture_ids')
23
+ @catalog_product_id = body.dig(:catalog_product_id) || body.dig('catalog_product_id')
24
+ @attributes = body.dig(:attributes) || body.dig('attributes')
25
+ end
26
+ end
27
+
28
+ def variation_id=(value)
29
+ @id = value
30
+ @variation_id = value
31
+ end
32
+
33
+ def save
34
+ if client.connected?
35
+ if valid?
36
+ @was_new = new?
37
+ @was_update = update?
38
+
39
+ if new?
40
+ json = client.variation.create(@item_id, new_layout)
41
+ else
42
+ json = client.variation.update(@item_id, @variation_id, update_layout)
43
+ end
44
+
45
+ if json['id']
46
+ @id = json['id']
47
+ @variation_id = json['id']
48
+ elsif json['error']
49
+ errors.add(:item, (json['cause'].to_a.empty? ? json['message'] : json['cause'].to_a.map { |e| e['message'] }.join('. ')))
50
+ else
51
+ errors.add(:item, "Ocorreu um erro ao enviar o item para o marketplace.")
52
+ end
53
+ end
54
+ else
55
+ errors.add(:client, "não conectado.")
56
+ end
57
+
58
+ errors.size.zero?
59
+ end
60
+
61
+ def destroy
62
+ if client.connected? && update?
63
+ client.variation.destroy(@item_id, @variation_id)
64
+ end
65
+ end
66
+
67
+ def self.find(client, item_id, variation_id)
68
+ if client.connected?
69
+ self.new(client, { "item_id" => item_id }.merge(client.variation.find(item_id, variation_id).to_h), { action: 'find' })
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def new_layout
76
+ layout = {}
77
+ layout[:attribute_combinations] = @attribute_combinations
78
+ layout[:price] = @price
79
+ layout[:available_quantity] = @available_quantity
80
+ layout[:picture_ids] = @picture_ids
81
+ layout[:catalog_product_id] = @catalog_product_id
82
+ layout[:attributes] = @attributes
83
+ layout
84
+ end
85
+
86
+ def update_layout
87
+ layout = new_layout
88
+ layout.delete(:catalog_product_id)
89
+ layout
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module Utils
5
+ class Error
6
+
7
+ include Enumerable
8
+
9
+ CALLBACKS_OPTIONS = %i[if unless on allow_nil allow_blank strict].freeze
10
+ MESSAGE_OPTIONS = [:message].freeze
11
+
12
+ attr_reader :messages, :details
13
+
14
+ def initialize(base)
15
+ @base = base
16
+ @messages = apply_default_array({})
17
+ @details = apply_default_array({})
18
+ end
19
+
20
+ def add(attribute, message = :invalid, options = {})
21
+ message = message.call if message.respond_to?(:call)
22
+ detail = normalize_detail(message, options)
23
+ message = normalize_message(attribute, message, options)
24
+ details[attribute.to_sym] << detail
25
+ messages[attribute.to_sym] << message
26
+ end
27
+
28
+ def size
29
+ @messages.values.flatten.size
30
+ end
31
+ alias count size
32
+
33
+ def generate_message(attribute, type = :invalid, _options = {})
34
+ :"errors.attributes.#{attribute}.#{type}"
35
+ end
36
+
37
+ def full_messages
38
+ @messages.values.flatten
39
+ end
40
+ alias to_a full_messages
41
+
42
+ private
43
+
44
+ def apply_default_array(hash)
45
+ hash.default_proc = proc { |h, key| h[key] = [] }
46
+ hash
47
+ end
48
+
49
+ def normalize_message(attribute, message, options)
50
+ case message
51
+ when Symbol
52
+ generate_message(attribute, message, except(options, *CALLBACKS_OPTIONS))
53
+ else
54
+ if message.start_with?(variable_name(attribute))
55
+ message
56
+ else
57
+ "#{variable_name(attribute)} #{message}"
58
+ end
59
+ end
60
+ end
61
+
62
+ def normalize_detail(message, options)
63
+ { error: message }.merge(except(options, *CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
64
+ end
65
+
66
+ def except(hash, *keys)
67
+ dup = hash.dup
68
+ keys.each { |key| dup.delete(key) }
69
+ dup
70
+ end
71
+
72
+ def variable_name(symbol)
73
+ symbol.to_s.tr('_', ' ').capitalize
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ # Módulo que simplifica as requisições HTTP/HTTPS
5
+ module HTTP
6
+
7
+ def self.get(uri, headers: {})
8
+ request = Net::HTTP::Get.new(uri)
9
+ MarketHub::HTTP.execute(uri, request, headers)
10
+ end
11
+
12
+ def self.post(uri, headers: {}, body: {})
13
+ request = Net::HTTP::Post.new(uri)
14
+ MarketHub::HTTP.execute(uri, request, headers, body)
15
+ end
16
+
17
+ def self.post_form(uri, headers: {}, body: {}, files: nil)
18
+ request = Net::HTTP::Post.new(uri)
19
+ type = :form_data
20
+ MarketHub::HTTP.execute(uri, request, headers, body, type, files)
21
+ end
22
+
23
+ def self.put(uri, headers: {}, body: {})
24
+ request = Net::HTTP::Put.new(uri)
25
+ MarketHub::HTTP.execute(uri, request, headers, body)
26
+ end
27
+
28
+ def self.put_form(uri, headers: {}, body: {}, files: nil)
29
+ request = Net::HTTP::Put.new(uri)
30
+ type = :form_data
31
+ MarketHub::HTTP.execute(uri, request, headers, body, type, files)
32
+ end
33
+
34
+ def self.delete(uri, headers: {})
35
+ request = Net::HTTP::Delete.new(uri)
36
+ MarketHub::HTTP.execute(uri, request, headers)
37
+ end
38
+
39
+ def self.execute(uri, request, headers = nil, body = nil, type = :raw_data, files = nil)
40
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
41
+ case type
42
+ when :raw_data
43
+ request.body = (body.is_a?(Hash) ? body.to_json : body) if body
44
+ when :form_data
45
+ request.form_data = body if body
46
+ request.set_form(files.map { |file| ['file', file, { filename: File.basename(file) }] }, 'multipart/form-data') if files
47
+ end
48
+
49
+ headers.each { |header, value| request[header] = value } if headers
50
+ http.request(request)
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ # Classe para autorização utilizando método OAuth 2.0
5
+ class OAuth20
6
+
7
+ attr_accessor :client_id
8
+ attr_accessor :client_secret
9
+ attr_accessor :redirect_uri
10
+
11
+ def initialize(client_id, client_secret, redirect_uri)
12
+ @client_id = client_id
13
+ @client_secret = client_secret
14
+ @redirect_uri = redirect_uri
15
+ end
16
+
17
+ def authorize_url(site, path, state = nil)
18
+ endpoint = URI::HTTPS.build(host: site, path: path)
19
+ endpoint.query = ["response_type=code", "client_id=#{@client_id}", "redirect_uri=#{@redirect_uri}"].join('&')
20
+ endpoint.query = [endpoint.query, "state=#{state}"].join('&') unless state.nil?
21
+ endpoint.to_s
22
+ end
23
+
24
+ def get_token(site, path, code)
25
+ endpoint = URI::HTTPS.build(host: site, path: path)
26
+ body = { grant_type: 'authorization_code', client_id: @client_id,
27
+ client_secret: @client_secret, code: code, redirect_uri: @redirect_uri }
28
+ response = MarketHub::HTTP.post_form(endpoint, body: body)
29
+ JSON.parse(response.body)
30
+ end
31
+
32
+ def renew_token(site, path, refresh_token)
33
+ endpoint = URI::HTTPS.build(host: site, path: path)
34
+ body = { grant_type: 'refresh_token', client_id: @client_id,
35
+ client_secret: @client_secret, refresh_token: refresh_token }
36
+ response = MarketHub::HTTP.post_form(endpoint, body: body)
37
+ JSON.parse(response.body)
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module Utils
5
+ module Validation
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ attr_reader :presences, :lengths, :numericals, :inclusions, :eachs
13
+
14
+ def validates_presence_of(*attr_names)
15
+ @presences ||= []
16
+ @presences = @presences << attr_names
17
+ end
18
+
19
+ def validates_length_of(*attr_names)
20
+ @lengths ||= []
21
+ @lengths = @lengths << attr_names
22
+ end
23
+
24
+ def validates_numericality_of(*attr_names)
25
+ @numericals ||= []
26
+ @numericals = @numericals << attr_names
27
+ end
28
+
29
+ def validates_inclusion_of(*attr_names)
30
+ @inclusions ||= []
31
+ @inclusions = @inclusions << attr_names
32
+ end
33
+
34
+ def validates_each(*attr_names, &block)
35
+ @eachs ||= {}
36
+ attr_names.each do |attr_name|
37
+ @eachs[attr_name] = block
38
+ end
39
+ end
40
+
41
+ def with_options(options, &block); end
42
+ end
43
+
44
+ def errors
45
+ @errors ||= MarketHub::Utils::Error.new(self)
46
+ end
47
+
48
+ def valid?
49
+ @errors = MarketHub::Utils::Error.new(self)
50
+
51
+ all_valid = true
52
+ all_valid = false unless check_eachs
53
+ all_valid = false unless check_presences
54
+ all_valid = false unless check_numericals
55
+ all_valid = false unless check_lengths
56
+ all_valid = false unless check_inclusions
57
+ all_valid
58
+ end
59
+
60
+ def invalid?
61
+ !valid?
62
+ end
63
+
64
+ private
65
+
66
+ def check_eachs
67
+ eachs = {}
68
+ eachs.merge!(self.class.superclass.superclass.eachs || {}) if self.class.superclass.superclass.respond_to?(:eachs)
69
+ eachs.merge!(self.class.superclass.eachs || {}) if self.class.superclass.respond_to?(:eachs)
70
+ eachs.merge!(self.class.eachs) if self.class.eachs
71
+ return true if eachs.keys.size.zero?
72
+
73
+ eachs.each do |attr_name, block|
74
+ value = ''
75
+ begin
76
+ value = send(attr_name)
77
+ rescue StandardError
78
+ end
79
+ block.call(self, attr_name, value)
80
+ end
81
+ errors.size.zero?
82
+ end
83
+
84
+ def check_presences
85
+ presences = []
86
+ if self.class.superclass.superclass.respond_to?(:presences)
87
+ presences = self.class.superclass.superclass.presences || []
88
+ end
89
+ presences += self.class.superclass.presences || [] if self.class.superclass.respond_to?(:presences)
90
+ presences += self.class.presences if self.class.presences
91
+ all_present = true
92
+ presences.each do |presence|
93
+ presence.select { |p| p.is_a? Symbol }.each do |variable|
94
+ if blank?(send(variable))
95
+ all_present = false
96
+ errors.add variable, presence[-1][:message]
97
+ end
98
+ end
99
+ end
100
+ all_present
101
+ end
102
+
103
+ def check_numericals
104
+ numericals = []
105
+ numericals = self.class.superclass.numericals || [] if self.class.superclass.respond_to?(:numericals)
106
+ numericals += self.class.numericals if self.class.numericals
107
+ return true unless numericals
108
+
109
+ all_numerical = true
110
+ numericals.each do |numerical|
111
+ numerical.select { |p| p.is_a? Symbol }.each do |variable|
112
+ if respond_to?(variable) && send(variable) && (send(variable).to_s =~ /\A[+-]?\d+\z/).nil?
113
+ all_numerical = false
114
+ errors.add variable, numerical[-1][:message]
115
+ end
116
+ end
117
+ end
118
+ all_numerical
119
+ end
120
+
121
+ def check_lengths
122
+ lengths = []
123
+ lengths = self.class.superclass.superclass.lengths || [] if self.class.superclass.superclass.respond_to?(:lengths)
124
+ lengths += self.class.superclass.lengths || [] if self.class.superclass.respond_to?(:lengths)
125
+ lengths += self.class.lengths if self.class.lengths
126
+ return true unless lengths
127
+
128
+ all_checked = true
129
+ lengths.each do |rule|
130
+ variable = rule[0]
131
+ next unless respond_to?(variable)
132
+
133
+ value = send(variable)
134
+ if rule[-1][:in]
135
+ if !value
136
+ all_checked = false
137
+ errors.add variable, rule[-1][:message]
138
+ elsif value.size < rule[-1][:in].first || value.size > rule[-1][:in].last
139
+ all_checked = false
140
+ errors.add variable, rule[-1][:message]
141
+ end
142
+ end
143
+ if rule[-1][:is]
144
+ if !value
145
+ all_checked = false
146
+ errors.add variable, rule[-1][:message]
147
+ elsif value.to_s.size != rule[-1][:is]
148
+ all_checked = false
149
+ errors.add variable, rule[-1][:message]
150
+ end
151
+ end
152
+ if rule[-1][:minimum] && rule[-1][:maximum]
153
+ if !value || value.size < rule[-1][:minimum] || value.size > rule[-1][:maximum]
154
+ all_checked = false
155
+ errors.add variable, rule[-1][:message]
156
+ end
157
+ elsif rule[-1][:maximum]
158
+ if value && value.size > rule[-1][:maximum]
159
+ all_checked = false
160
+ errors.add variable, rule[-1][:message]
161
+ end
162
+ end
163
+ end
164
+ all_checked
165
+ end
166
+
167
+ def check_inclusions
168
+ inclusions = []
169
+ if self.class.superclass.superclass.respond_to?(:inclusions)
170
+ inclusions = self.class.superclass.superclass.inclusions || []
171
+ end
172
+ inclusions += self.class.superclass.inclusions || [] if self.class.superclass.respond_to?(:inclusions)
173
+ inclusions += self.class.inclusions if self.class.inclusions
174
+ return true unless inclusions
175
+
176
+ all_checked = true
177
+ inclusions.each do |rule|
178
+ variable = rule[0]
179
+ next unless respond_to?(variable)
180
+
181
+ value = send(variable)
182
+ next unless value
183
+
184
+ next unless rule[-1][:in]
185
+
186
+ unless rule[-1][:in].include?(value)
187
+ all_checked = false
188
+ errors.add variable, rule[-1][:message]
189
+ end
190
+ end
191
+ all_checked
192
+ end
193
+
194
+ def variable_name(symbol)
195
+ symbol.to_s.tr('_', ' ').capitalize
196
+ end
197
+
198
+ def blank?(obj)
199
+ return obj !~ /\S/ if obj.is_a? String
200
+
201
+ obj.respond_to?(:empty?) ? obj.empty? : !obj
202
+ end
203
+ end
204
+
205
+ end
206
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MarketHub
4
- VERSION = "0.1.0"
4
+ VERSION = "0.23.5"
5
5
  end
data/lib/market_hub.rb CHANGED
@@ -1,8 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "market_hub/version"
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ require 'market_hub/base'
8
+ require 'market_hub/configuration'
9
+ require 'market_hub/exception'
10
+ require 'market_hub/version'
11
+
12
+ require 'market_hub/utils/error'
13
+ require 'market_hub/utils/http'
14
+ require 'market_hub/utils/o_auth_20'
15
+ require 'market_hub/utils/validation'
16
+
17
+ require 'market_hub/models/base'
18
+ require 'market_hub/models/mercado_livre/item'
19
+ require 'market_hub/models/mercado_livre/variation'
20
+
21
+ require 'market_hub/api/base'
22
+ require 'market_hub/api/mercado_livre/client'
23
+ require 'market_hub/api/mercado_livre/authorization'
24
+ require 'market_hub/api/mercado_livre/category'
25
+ require 'market_hub/api/mercado_livre/publication_type'
26
+ require 'market_hub/api/mercado_livre/item'
27
+ require 'market_hub/api/mercado_livre/description'
28
+ require 'market_hub/api/mercado_livre/image'
29
+ require 'market_hub/api/mercado_livre/user'
30
+ require 'market_hub/api/mercado_livre/catalog'
31
+ require 'market_hub/api/mercado_livre/variation'
32
+ require 'market_hub/api/mercado_livre/question_answer'
33
+ require 'market_hub/api/mercado_livre/order'
34
+ require 'market_hub/api/mercado_livre/shipment'
35
+ require 'market_hub/api/mercado_livre/invoice'
36
+
37
+ require 'market_hub/client'
4
38
 
5
39
  module MarketHub
6
- class Error < StandardError; end
7
- # Your code goes here...
40
+ # Personalize as configurações padrão da biblioteca usando bloco
41
+ # MarketHub.configure do |config|
42
+ # config.meli_client_id = "xxx"
43
+ # config.meli_client_secret = "xxx"
44
+ # end
45
+ # Se nenhum bloco for fornecido, retorna o objeto de configuração padrão
46
+ def self.configure
47
+ if block_given?
48
+ yield(Configuration.default)
49
+ else
50
+ Configuration.default
51
+ end
52
+ end
8
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: market_hub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.23.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrique Shiraishi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2024-10-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -22,6 +22,32 @@ files:
22
22
  - README.md
23
23
  - Rakefile
24
24
  - lib/market_hub.rb
25
+ - lib/market_hub/api/base.rb
26
+ - lib/market_hub/api/mercado_livre/authorization.rb
27
+ - lib/market_hub/api/mercado_livre/catalog.rb
28
+ - lib/market_hub/api/mercado_livre/category.rb
29
+ - lib/market_hub/api/mercado_livre/client.rb
30
+ - lib/market_hub/api/mercado_livre/description.rb
31
+ - lib/market_hub/api/mercado_livre/image.rb
32
+ - lib/market_hub/api/mercado_livre/invoice.rb
33
+ - lib/market_hub/api/mercado_livre/item.rb
34
+ - lib/market_hub/api/mercado_livre/order.rb
35
+ - lib/market_hub/api/mercado_livre/publication_type.rb
36
+ - lib/market_hub/api/mercado_livre/question_answer.rb
37
+ - lib/market_hub/api/mercado_livre/shipment.rb
38
+ - lib/market_hub/api/mercado_livre/user.rb
39
+ - lib/market_hub/api/mercado_livre/variation.rb
40
+ - lib/market_hub/base.rb
41
+ - lib/market_hub/client.rb
42
+ - lib/market_hub/configuration.rb
43
+ - lib/market_hub/exception.rb
44
+ - lib/market_hub/models/base.rb
45
+ - lib/market_hub/models/mercado_livre/item.rb
46
+ - lib/market_hub/models/mercado_livre/variation.rb
47
+ - lib/market_hub/utils/error.rb
48
+ - lib/market_hub/utils/http.rb
49
+ - lib/market_hub/utils/o_auth_20.rb
50
+ - lib/market_hub/utils/validation.rb
25
51
  - lib/market_hub/version.rb
26
52
  - sig/market_hub.rbs
27
53
  homepage: https://github.com/henriqueshiraishi/ruby-market_hub