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,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API de Pedidos
7
+ class Order
8
+
9
+ attr_accessor :access_token
10
+ attr_accessor :user_id
11
+
12
+ def initialize(access_token, user_id)
13
+ @access_token = access_token
14
+ @user_id = user_id
15
+ end
16
+
17
+ # Principais status existentes: paid, cancelled e invalid
18
+ def all(status: 'paid', options: {})
19
+ host = MarketHub.configure.meli_api_uri
20
+ path = "/orders/search"
21
+ endpoint = URI::HTTPS.build(host: host, path: path)
22
+ params = { seller: @user_id }.merge(options)
23
+ params.merge!({ "order.status" => status }) if status
24
+ endpoint.query = URI.encode_www_form(params)
25
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
26
+ JSON.parse(response.body)
27
+ end
28
+
29
+ # Principais status existentes: paid, cancelled e invalid
30
+ def recent(status: 'paid', options: {})
31
+ host = MarketHub.configure.meli_api_uri
32
+ path = "/orders/search/recent"
33
+ endpoint = URI::HTTPS.build(host: host, path: path)
34
+ params = { seller: @user_id }.merge(options)
35
+ params.merge!({ "order.status" => status }) if status
36
+ endpoint.query = URI.encode_www_form(params)
37
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
38
+ JSON.parse(response.body)
39
+ end
40
+
41
+ def find(order_id)
42
+ host = MarketHub.configure.meli_api_uri
43
+ path = "/orders/#{order_id}"
44
+ endpoint = URI::HTTPS.build(host: host, path: path)
45
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
46
+ JSON.parse(response.body)
47
+ end
48
+
49
+ def notes(order_id)
50
+ host = MarketHub.configure.meli_api_uri
51
+ path = "/orders/#{order_id}/notes"
52
+ endpoint = URI::HTTPS.build(host: host, path: path)
53
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
54
+ JSON.parse(response.body)
55
+ end
56
+
57
+ def billing_info(order_id)
58
+ host = MarketHub.configure.meli_api_uri
59
+ path = "/orders/#{order_id}/billing_info"
60
+ endpoint = URI::HTTPS.build(host: host, path: path)
61
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
62
+ JSON.parse(response.body)
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API de Tipos de Publicação
7
+ class PublicationType
8
+
9
+ attr_accessor :access_token
10
+
11
+ def initialize(access_token)
12
+ @access_token = access_token
13
+ end
14
+
15
+ def listing_types(site_id, listing_type_id = nil)
16
+ host = MarketHub.configure.meli_api_uri
17
+ path = "/sites/#{site_id}/listing_types/"
18
+ path = path + listing_type_id.to_s unless listing_type_id.nil?
19
+ endpoint = URI::HTTPS.build(host: host, path: path)
20
+ response = MarketHub::HTTP.get(endpoint)
21
+ JSON.parse(response.body)
22
+ end
23
+
24
+ def listing_exposures(site_id,listing_exposure_id = nil)
25
+ host = MarketHub.configure.meli_api_uri
26
+ path = "/sites/#{site_id}/listing_exposures/"
27
+ path = path + listing_exposure_id.to_s unless listing_exposure_id.nil?
28
+ endpoint = URI::HTTPS.build(host: host, path: path)
29
+ response = MarketHub::HTTP.get(endpoint)
30
+ JSON.parse(response.body)
31
+ end
32
+
33
+ def listing_types_availables(reference_id, category_id = nil)
34
+ host = MarketHub.configure.meli_api_uri
35
+ params = {}
36
+ if category_id.nil?
37
+ path = "/items/#{reference_id}/available_listing_types"
38
+ else
39
+ path = "/users/#{reference_id}/available_listing_types"
40
+ params = params.merge({ category_id: category_id })
41
+ end
42
+ endpoint = URI::HTTPS.build(host: host, path: path)
43
+ endpoint.query = URI.encode_www_form(params)
44
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
45
+ JSON.parse(response.body)
46
+ end
47
+
48
+ def listing_types_downgrades(item_id)
49
+ host = MarketHub.configure.meli_api_uri
50
+ path = "/items/#{item_id}/available_upgrades"
51
+ endpoint = URI::HTTPS.build(host: host, path: path)
52
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
53
+ JSON.parse(response.body)
54
+ end
55
+
56
+ def listing_types_upgrades(item_id)
57
+ host = MarketHub.configure.meli_api_uri
58
+ path = "/items/#{item_id}/available_downgrades"
59
+ endpoint = URI::HTTPS.build(host: host, path: path)
60
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
61
+ JSON.parse(response.body)
62
+ end
63
+
64
+ def update(item_id, listing_type_id)
65
+ host = MarketHub.configure.meli_api_uri
66
+ path = "/items/#{item_id}/listing_type"
67
+ endpoint = URI::HTTPS.build(host: host, path: path)
68
+ response = MarketHub::HTTP.post(endpoint, headers: { authorization: "Bearer #{@access_token}" }, body: { id: listing_type_id })
69
+ JSON.parse(response.body)
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API de Perguntas e Respostas
7
+ class QuestionAnswer
8
+
9
+ attr_accessor :access_token
10
+ attr_accessor :user_id
11
+
12
+ def initialize(access_token, user_id)
13
+ @access_token = access_token
14
+ @user_id = user_id
15
+ end
16
+
17
+ def metrics
18
+ host = MarketHub.configure.meli_api_uri
19
+ path = "/users/#{@user_id}/questions/response_time"
20
+ endpoint = URI::HTTPS.build(host: host, path: path)
21
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
22
+ JSON.parse(response.body)
23
+ end
24
+
25
+ def all(options = {})
26
+ host = MarketHub.configure.meli_api_uri
27
+ path = "/questions/search"
28
+ params = { seller_id: @user_id, api_version: 4 }.merge(options)
29
+ endpoint = URI::HTTPS.build(host: host, path: path)
30
+ endpoint.query = URI.encode_www_form(params)
31
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
32
+ JSON.parse(response.body)
33
+ end
34
+
35
+ def find(question_id)
36
+ host = MarketHub.configure.meli_api_uri
37
+ path = "/questions/#{question_id}"
38
+ endpoint = URI::HTTPS.build(host: host, path: path)
39
+ endpoint.query = URI.encode_www_form({ api_version: 4 })
40
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
41
+ JSON.parse(response.body)
42
+ end
43
+
44
+ def anwser(question_id, text)
45
+ host = MarketHub.configure.meli_api_uri
46
+ path = "/answers"
47
+ body = { question_id: question_id, text: text }
48
+ endpoint = URI::HTTPS.build(host: host, path: path)
49
+ response = MarketHub::HTTP.post(endpoint, headers: { authorization: "Bearer #{@access_token}" }, body: body)
50
+ JSON.parse(response.body)
51
+ end
52
+
53
+ def destroy(question_id)
54
+ host = MarketHub.configure.meli_api_uri
55
+ path = "/questions/#{question_id}"
56
+ endpoint = URI::HTTPS.build(host: host, path: path)
57
+ response = MarketHub::HTTP.delete(endpoint, headers: { authorization: "Bearer #{@access_token}" })
58
+ JSON.parse(response.body)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API de Transporte
7
+ class Shipment
8
+
9
+ attr_accessor :access_token
10
+ attr_reader :types
11
+
12
+ def initialize(access_token)
13
+ @access_token = access_token
14
+ @types = %w(items costs payments lead_time delays history carrier billing_info)
15
+ end
16
+
17
+ def find(shipment_id, type = nil)
18
+ host = MarketHub.configure.meli_api_uri
19
+ path = "/shipments/#{shipment_id}/"
20
+ path = path + type.to_s unless type.nil?
21
+ endpoint = URI::HTTPS.build(host: host, path: path)
22
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
23
+ JSON.parse(response.body)
24
+ end
25
+
26
+ def labels(shipment_ids, response_type = 'pdf')
27
+ shipment_ids = shipment_ids.join(',') if shipment_ids.is_a?(Array)
28
+ host = MarketHub.configure.meli_api_uri
29
+ path = "/shipment_labels"
30
+ params = { shipment_ids: shipment_ids, response_type: response_type }
31
+ endpoint = URI::HTTPS.build(host: host, path: path)
32
+ endpoint.query = URI.encode_www_form(params)
33
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
34
+ try_to_convert_to_json(response.body)
35
+ end
36
+
37
+ private
38
+
39
+ def try_to_convert_to_json(body)
40
+ JSON.parse(body)
41
+ rescue
42
+ body
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API do Usuário
7
+ class User
8
+
9
+ attr_accessor :access_token
10
+
11
+ def initialize(access_token)
12
+ @access_token = access_token
13
+ end
14
+
15
+ def me
16
+ host = MarketHub.configure.meli_api_uri
17
+ path = "/users/me"
18
+ endpoint = URI::HTTPS.build(host: host, path: path)
19
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
20
+ JSON.parse(response.body)
21
+ end
22
+
23
+ def currency
24
+ host = MarketHub.configure.meli_api_uri
25
+ path = "/classified_locations/countries/#{me['country_id']}"
26
+ endpoint = URI::HTTPS.build(host: host, path: path)
27
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
28
+ JSON.parse(response.body)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module API
5
+ module MercadoLivre
6
+ # Classe API de Variação
7
+ class Variation
8
+
9
+ attr_accessor :access_token
10
+
11
+ def initialize(access_token)
12
+ @access_token = access_token
13
+ end
14
+
15
+ def all(item_id, params = {})
16
+ host = MarketHub.configure.meli_api_uri
17
+ path = "/items/#{item_id}/variations/"
18
+ if params[:variation_id]
19
+ path = path + params[:variation_id]
20
+ params.delete(:variation_id)
21
+ end
22
+ endpoint = URI::HTTPS.build(host: host, path: path)
23
+ endpoint.query = URI.encode_www_form(params)
24
+ response = MarketHub::HTTP.get(endpoint, headers: { authorization: "Bearer #{@access_token}" })
25
+ JSON.parse(response.body)
26
+ end
27
+
28
+ def find(item_id, variation_id)
29
+ all(item_id, { variation_id: variation_id })
30
+ end
31
+
32
+ def create(item_id, body)
33
+ host = MarketHub.configure.meli_api_uri
34
+ path = "/items/#{item_id}/variations"
35
+ endpoint = URI::HTTPS.build(host: host, path: path)
36
+ response = MarketHub::HTTP.post(endpoint, headers: { authorization: "Bearer #{@access_token}" }, body: body)
37
+ JSON.parse(response.body)
38
+ end
39
+
40
+ def update(item_id, variation_id, body)
41
+ host = MarketHub.configure.meli_api_uri
42
+ path = "/items/#{item_id}/variations/#{variation_id}"
43
+ endpoint = URI::HTTPS.build(host: host, path: path)
44
+ response = MarketHub::HTTP.put(endpoint, headers: { authorization: "Bearer #{@access_token}" }, body: body)
45
+ JSON.parse(response.body)
46
+ end
47
+
48
+ def destroy(item_id, variation_id)
49
+ host = MarketHub.configure.meli_api_uri
50
+ path = "/items/#{item_id}/variations/#{variation_id}"
51
+ endpoint = URI::HTTPS.build(host: host, path: path)
52
+ response = MarketHub::HTTP.delete(endpoint, headers: { authorization: "Bearer #{@access_token}" })
53
+ JSON.parse(response.body)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ # Classe genérica para todas outras classes base da biblioteca
5
+ class Base
6
+
7
+ def initialize
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ # Principal classe que manipula todas integrações
5
+ class Client < MarketHub::API::Base
6
+
7
+ def initialize
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ # Classe base para parametrização da biblioteca
5
+ class Configuration
6
+
7
+ attr_accessor :currency_id
8
+
9
+ attr_accessor :meli_client_id
10
+ attr_accessor :meli_client_secret
11
+ attr_accessor :meli_redirect_uri
12
+ attr_accessor :meli_auth_uri
13
+ attr_accessor :meli_api_uri
14
+
15
+ def initialize
16
+ @meli_client_id = nil
17
+ @meli_client_secret = nil
18
+ @meli_redirect_uri = nil
19
+ @meli_auth_uri = 'auth.mercadolivre.com.br'
20
+ @meli_api_uri = 'api.mercadolibre.com'
21
+ @currency_id = 'BRL'
22
+ end
23
+
24
+ def self.default
25
+ @default ||= Configuration.new
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+
5
+ class Error < StandardError
6
+ end
7
+
8
+ class NotImplemented < RuntimeError
9
+ end
10
+
11
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module Models
5
+ # Classe base para todos os modelos (Models)
6
+ class Base < MarketHub::Base
7
+
8
+ include MarketHub::Utils::Validation
9
+
10
+ attr_reader :id
11
+ attr_reader :client
12
+ attr_reader :body
13
+
14
+ def initialize(client, body = {}, options = {})
15
+ @client = client
16
+ @body = body
17
+ @options = options
18
+ end
19
+
20
+ def save
21
+ raise MarketHub::NotImplemented, 'Sobreescreva este método na classe referente ao marketplace que você esta criando'
22
+ end
23
+
24
+ def destroy
25
+ raise MarketHub::NotImplemented, 'Sobreescreva este método na classe referente ao marketplace que você esta criando'
26
+ end
27
+
28
+ def active!
29
+ raise MarketHub::NotImplemented, 'Sobreescreva este método na classe referente ao marketplace que você esta criando'
30
+ end
31
+
32
+ def paused!
33
+ raise MarketHub::NotImplemented, 'Sobreescreva este método na classe referente ao marketplace que você esta criando'
34
+ end
35
+
36
+ def new?
37
+ @id.to_s == "" ? true : false
38
+ end
39
+
40
+ def update?
41
+ !new?
42
+ end
43
+
44
+ def self.find(client, id)
45
+ if client.connected?
46
+ self.new(client, client.find(id), { action: 'find' })
47
+ end
48
+ end
49
+
50
+ def self.create(client, body)
51
+ if client.connected?
52
+ object = self.new(client, body, { action: 'create' })
53
+ object.save
54
+ object
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarketHub
4
+ module Models
5
+ module MercadoLivre
6
+ # Classe que representa um Item no Mercado Livre
7
+ class Item < MarketHub::Models::Base
8
+
9
+ attr_accessor :item_id, :title, :description, :category_id, :price, :available_quantity, :sale_terms, :listing_type_id, :condition, :pictures,
10
+ :video_id, :local_pick_up, :free_shipping, :attributes, :status, :catalog_product_id, :channel_markeplace, :channel_mshops
11
+
12
+ validates_presence_of :title, :category_id, :price, :available_quantity, :listing_type_id, :attributes, message: 'não pode estar em branco.'
13
+
14
+ def initialize(client, body = {}, options = {})
15
+ super(client, body, options)
16
+ unless body.empty?
17
+ @id = body.dig(:item_id) || body.dig('id')
18
+ @item_id = body.dig(:item_id) || body.dig('id')
19
+ @title = body.dig(:title) || body.dig('title')
20
+ @description = body.dig(:description) || (client.description.find(@item_id).dig('plain_text') if options[:action] == 'find' && @item_id)
21
+ @category_id = body.dig(:category_id) || body.dig('category_id')
22
+ @price = (body.dig(:price) || body.dig('price')).to_f
23
+ @available_quantity = body.dig(:available_quantity) || body.dig('available_quantity')
24
+ @sale_terms = body.dig(:sale_terms) || body.dig('sale_terms')
25
+ @listing_type_id = body.dig(:listing_type_id) || body.dig('listing_type_id')
26
+ @condition = body.dig(:condition) || body.dig('condition')
27
+ @pictures = body.dig(:pictures) || body.dig('pictures')
28
+ @video_id = body.dig(:video_id) || body.dig('video_id')
29
+ @local_pick_up = body.dig(:local_pick_up) || body.dig('shipping', 'local_pick_up')
30
+ @free_shipping = body.dig(:free_shipping) || body.dig('shipping', 'free_shipping')
31
+ @attributes = body.dig(:attributes) || body.dig('attributes')
32
+ @status = body.dig(:status) || body.dig('status')
33
+ @catalog_product_id = body.dig(:catalog_product_id) || body.dig('catalog_product_id')
34
+ @channel_markeplace = (body.dig('channels') ? body.dig('channels').include?("marketplace") : body.dig(:channel_markeplace))
35
+ @channel_mshops = (body.dig('channels') ? body.dig('channels').include?("mshops") : body.dig(:channel_mshops))
36
+ end
37
+ end
38
+
39
+ def item_id=(value)
40
+ @id = value
41
+ @item_id = value
42
+ end
43
+
44
+ def save
45
+ if client.connected?
46
+ if valid?
47
+ @was_new = new?
48
+ @was_update = update?
49
+
50
+ if new?
51
+ json = client.item.create(new_layout)
52
+ else
53
+ json = client.item.update(@item_id, update_layout)
54
+ end
55
+
56
+ if json['id']
57
+ @id = json['id']
58
+ @item_id = json['id']
59
+ if !@description.to_s.empty? && (@was_new || client.description.find(@item_id).empty?)
60
+ client.description.create(@item_id, @description)
61
+ else
62
+ client.description.update(@item_id, @description)
63
+ end
64
+ elsif json['error']
65
+ errors.add(:item, (json['cause'].to_a.empty? ? json['message'] : json['cause'].to_a.map { |e| e['message'] }.join('. ')))
66
+ else
67
+ errors.add(:item, "Ocorreu um erro ao enviar o item para o marketplace.")
68
+ end
69
+ end
70
+ else
71
+ errors.add(:client, "não conectado.")
72
+ end
73
+
74
+ errors.size.zero?
75
+ end
76
+
77
+ def destroy
78
+ if client.connected? && update?
79
+ client.item.destroy(@item_id)
80
+ end
81
+ end
82
+
83
+ def active!
84
+ @status = 'active'
85
+ save
86
+ end
87
+
88
+ def paused!
89
+ @status = 'paused'
90
+ save
91
+ end
92
+
93
+ private
94
+
95
+ def new_layout
96
+ layout = {}
97
+ layout[:title] = @title
98
+ layout[:category_id] = @category_id
99
+ layout[:price] = @price
100
+ layout[:currency_id] = Configuration.default.currency_id
101
+ layout[:available_quantity] = @available_quantity
102
+ layout[:sale_terms] = @sale_terms
103
+ layout[:buying_mode] = "buy_it_now"
104
+ layout[:listing_type_id] = @listing_type_id
105
+ layout[:condition] = @condition
106
+ layout[:pictures] = @pictures
107
+ layout[:video_id] = @video_id
108
+ layout[:shipping] = { local_pick_up: @local_pick_up, free_shipping: @free_shipping }
109
+ layout[:attributes] = @attributes
110
+ layout[:status] = @status
111
+ layout[:catalog_product_id] = @catalog_product_id
112
+ layout[:catalog_listing] = !(@catalog_product_id.to_s == "")
113
+ layout[:channels] = []
114
+ layout[:channels].push("marketplace") if @channel_markeplace
115
+ layout[:channels].push("mshops") if @channel_mshops
116
+ layout
117
+ end
118
+
119
+ def update_layout
120
+ @has_bids = (client.item.find(@item_id).dig('sold_quantity').to_i > 0) unless @has_bids
121
+
122
+ layout = new_layout
123
+ if @has_bids
124
+ layout.delete(:title)
125
+ layout.delete(:category_id)
126
+ layout.delete(:condition)
127
+ end
128
+ layout.delete(:currency_id)
129
+ layout.delete(:buying_mode)
130
+ layout.delete(:listing_type_id)
131
+ layout.delete(:catalog_product_id)
132
+ layout.delete(:catalog_listing)
133
+ layout
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+ end