bling-ruby-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ module Bling
4
+ module API
5
+ class Parser
6
+
7
+ def initialize(text, klass_name)
8
+ @text, @klass_name = text, klass_name
9
+ end
10
+
11
+ def result
12
+ raw_response = JSON.parse(@text)
13
+ Translator.translate_hash(raw_response, to: :en)
14
+ end
15
+
16
+ def records
17
+ raw_records = result[:return][plural_klass_name]
18
+ return [] if raw_records.nil?
19
+ raw_records.each_with_object([]) { |record, result| result << Record.new(record[@klass_name]) }
20
+ end
21
+
22
+ private
23
+
24
+ def plural_klass_name
25
+ @klass_name.to_s.pluralize.to_sym
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,143 @@
1
+ module Bling
2
+ module API
3
+ # This class is used to make requests to all available
4
+ # actions related to products in Bling api. Is strongly recommended
5
+ # to use the Bling::API module wrapper
6
+ #
7
+ class Product < Request
8
+
9
+ # Get a list of available products
10
+ #
11
+ # @example
12
+ # products = Bling::API::Product.new.list
13
+ #
14
+ # @return [[Record]] Call products index and return an array with records
15
+ #
16
+ def list
17
+ get_request(t_url(:products))
18
+ end
19
+
20
+ # Get a specific object based on product_id
21
+ #
22
+ # @example
23
+ # product = Bling::API::Product.new.get
24
+ #
25
+ # @param [Integer,String] product_id The product id in Bling
26
+ #
27
+ # @return [[Record]] Call product show and return an arrayn with one record
28
+ #
29
+ def get(product_id)
30
+ get_request(t_url(:product, product_id))
31
+ end
32
+
33
+ # Insert a product in Bling
34
+ #
35
+ # @example
36
+ # product = Bling::API::Product.new.create(
37
+ # {
38
+ # code: '92314',
39
+ # description: 'Awesome product',
40
+ # additional_description: 'In lovely colors',
41
+ # unit: 'Pc',
42
+ # price: 20.50,
43
+ # cost_price: 14.30,
44
+ # raw_weight: 2,
45
+ # weight: 1.8,
46
+ # tax_category: '1000.01.01',
47
+ # origin: 0,
48
+ # quantity: 10,
49
+ # gtin: 832222,
50
+ # gtin_package: 13414,
51
+ # width: 25,
52
+ # height: 15,
53
+ # depth: 10,
54
+ # min_quantity: 1,
55
+ # max_quantity: 200
56
+ # }
57
+ # )
58
+ #
59
+ # @param [Hash] params A hash with product options
60
+ #
61
+ # @return [[Record]] Call product show and return an array with one record
62
+ #
63
+ def create(params)
64
+ @params = params
65
+ post_request(t_url(:product), parsed_xml)
66
+ end
67
+
68
+ # Update a product in Bling
69
+ #
70
+ # @example
71
+ # product = Bling::API::Product.new.create(
72
+ # {
73
+ # code: '92314',
74
+ # description: 'Awesome product',
75
+ # additional_description: 'In lovely colors',
76
+ # unit: 'Pc',
77
+ # price: 20.50,
78
+ # cost_price: 14.30,
79
+ # raw_weight: 2,
80
+ # weight: 1.8,
81
+ # tax_category: '1000.01.01',
82
+ # origin: 0,
83
+ # quantity: 10,
84
+ # gtin: 832222,
85
+ # gtin_package: 13414,
86
+ # width: 25,
87
+ # height: 15,
88
+ # depth: 10,
89
+ # min_quantity: 1,
90
+ # max_quantity: 200
91
+ # }
92
+ # )
93
+ #
94
+ # @param [Integer, String] product_id The product id in Bling
95
+ # @param [Hash] params A hash with product options
96
+ #
97
+ # @return [[Record]] Call product show and return an array with one record
98
+ #
99
+ def update(product_id, params)
100
+ @params = params
101
+ post_request(t_url(:product, product_id), parsed_xml)
102
+ end
103
+
104
+ # Delete a product in Bling
105
+ #
106
+ # @example
107
+ # Bling::API::Product.new.delete(1)
108
+ #
109
+ # @param [Integer,String] product_id The product id in Bling
110
+ #
111
+ # @return [[Record]] Call product show and return an array with one record
112
+ #
113
+ def delete(product_id)
114
+ delete_request(t_url(:product, product_id))
115
+ end
116
+
117
+ private
118
+
119
+ def parsed_xml
120
+ @params = translate(@params) unless Bling.config.default_language == :en
121
+ validate(@params, :description, :price)
122
+ build_missing_keys
123
+ product_template % @params
124
+ end
125
+
126
+ def build_missing_keys
127
+ xml_nodes.each do |node|
128
+ @params[node] = nil unless @params.has_key?(node)
129
+ end
130
+ end
131
+
132
+ def xml_nodes
133
+ %i(code description
134
+ additional_description unit price
135
+ cost_price raw_weight weight
136
+ tax_category origin quantity gtin
137
+ gtin_package width height depth
138
+ min_quantity max_quantity cest)
139
+ end
140
+
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,25 @@
1
+ module Bling
2
+ module API
3
+ class Record
4
+
5
+ # @return [Hash] The original hash attributes passed on initialize
6
+ attr_reader :attrs
7
+
8
+ # @params [Hash] A hash that will generate accessors for each key
9
+ def initialize(hash)
10
+ @attrs = hash
11
+ end
12
+
13
+ private
14
+
15
+ def method_missing(method, *args, &block)
16
+ if attrs.has_key?(method)
17
+ attrs[method]
18
+ else
19
+ super(method, args, block)
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ module Bling
2
+ module API
3
+ class Request
4
+
5
+ private
6
+
7
+ def get_request(url)
8
+ Client.new(url, {}, klass_name).get
9
+ end
10
+
11
+ def post_request(url, params)
12
+ Client.new(url, params, klass_name).post
13
+ end
14
+
15
+ def put_request(url, params)
16
+ Client.new(url, params, klass_name).post
17
+ end
18
+
19
+ def delete_request(url)
20
+ Client.new(url, {}, klass_name).delete
21
+ end
22
+
23
+ def klass_name
24
+ self.class.to_s.split('::').last.downcase.to_sym
25
+ end
26
+
27
+ def t_url(url, id=nil)
28
+ Translator.translate_url(url, id: id)
29
+ end
30
+
31
+ def translate(params)
32
+ Translator.translate_hash(params)
33
+ end
34
+
35
+ def validate(params, *required_params)
36
+ required_params.each do |param|
37
+ if params[param].nil? || params[param] =~ /^\s*$/
38
+ raise ArgumentError, "The required parameter `:#{param}' is missing."
39
+ end
40
+ end
41
+ end
42
+
43
+ def method_missing(method, *args, &block)
44
+ if method.to_s =~/\A.+_template\z/
45
+ IO.read(File.join(File.dirname(__FILE__), "templates", method.to_s))
46
+ else
47
+ super(method, args, &block)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ module Bling
2
+ module API
3
+ class Response
4
+
5
+ # @return [Net::HTTPResponse] The response object returned by Net::HTTP.
6
+ attr_reader :http_response
7
+
8
+ # @param [Net::HTTPResponse] http_response The response object returned by Net::HTTP.
9
+ def initialize(http_response, klass_name)
10
+ @http_response = http_response
11
+ @klass_name = klass_name
12
+ end
13
+
14
+ # @return [String] The raw body of the response object.
15
+ def body
16
+ @http_response.body
17
+ end
18
+
19
+ # @return [Boolean] Whether or not the request was successful.
20
+ def success?
21
+ !http_failure? && without_errors
22
+ end
23
+
24
+ # @return [Boolean] Whether or not the HTTP request was a success.
25
+ def http_failure?
26
+ !@http_response.is_a?(Net::HTTPSuccess)
27
+ end
28
+
29
+ # @return [Array] with parsed response body.
30
+ def records
31
+ parsed_response.records if success?
32
+ end
33
+
34
+ private
35
+
36
+ def without_errors
37
+ parsed_response.result[:return] && parsed_response.result[:return][:errors].nil?
38
+ end
39
+
40
+ def parsed_response
41
+ @parsed_response ||= Parser.new(body, @klass_name)
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ <parcela>
2
+ <data>%{date}</data>
3
+ <vlr>%{amount}</vlr>
4
+ <obs>%{additional_info}</obs>
5
+ </parcela>
6
+
@@ -0,0 +1,8 @@
1
+ <item>
2
+ <codigo>%{code}</codigo>
3
+ <descricao>%{description}</descricao>
4
+ <un>%{unit}</un>
5
+ <qtde>%{item_quantity}</qtde>
6
+ <vlr_unit>%{price}</vlr_unit>
7
+ </item>
8
+
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <pedido>
3
+ <data>%{date}</data>
4
+ <numero>%{order_number}</numero>
5
+ <numero_loja>%{ecommerce_order_number}</numero_loja>
6
+ <loja>%{store}</loja>
7
+ <nat_operacao>%{selling_category}</nat_operacao>
8
+ <cliente>
9
+ <nome>%{name}</nome>
10
+ <tipoPessoa>%{tax_type}</tipoPessoa>
11
+ <endereco>%{address}</endereco>
12
+ <cpf_cnpj>%{document}</cpf_cnpj>
13
+ <ie_rg>%{ie_rg}</ie_rg>
14
+ <contribuinte>%{tax_classification}</contribuinte>
15
+ <numero>%{number}</numero>
16
+ <complemento>%{additional_address}</complemento>
17
+ <bairro>%{neighborhood}</bairro>
18
+ <cep>%{zipcode}</cep>
19
+ <cidade>%{city}</cidade>
20
+ <uf>%{state}</uf>
21
+ <fone>%{phone}</fone>
22
+ <celular>%{cellphone}</celular>
23
+ <email>%{email}</email>
24
+ </cliente>
25
+ <transporte>
26
+ <transportadora>%{carrier}</transportadora>
27
+ <tipo_frete>%{shipment_type}</tipo_frete>
28
+ <servico_correios>%{correios_service}</servico_correios>
29
+ <dados_etiqueta>
30
+ <nome>%{shipment_label_name}</nome>
31
+ <endereco>%{shipment_label_address}</endereco>
32
+ <numero>%{shipment_label_number}</numero>
33
+ <complemento>%{shipment_label_additional_address}</complemento>
34
+ <municipio>%{shipment_label_city}</municipio>
35
+ <uf>%{shipment_label_state}</uf>
36
+ <cep>%{shipment_label_zipcode}</cep>
37
+ <bairro>%{shipment_label_neighborhood}</bairro>
38
+ </dados_etiqueta>
39
+ </transporte>
40
+ <itens>%{items}</itens>
41
+ <parcelas>%{installments}</parcelas>
42
+ <vlr_frete>%{shipment_amount}</vlr_frete>
43
+ <vlr_desconto>%{discount_amount}</vlr_desconto>
44
+ <obs>%{additional_info}</obs>
45
+ <obs_internas>%{private_additional_info}</obs_internas>
46
+ </pedido>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <pedido>
3
+ <situacao>%{:status}</situacao>
4
+ </pedido>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <produto>
3
+ <codigo>%{code}</codigo>
4
+ <descricao>%{description}</descricao>
5
+ <descricaoComplementar>%{additional_description}</descricaoComplementar>
6
+ <un>%{unit}</un>
7
+ <vlr_unit>%{price}</vlr_unit>
8
+ <preco_custo>%{cost_price}</preco_custo>
9
+ <peso_bruto>%{raw_weight}</peso_bruto>
10
+ <peso_liq>%{weight}</peso_liq>
11
+ <class_fiscal>%{tax_category}</class_fiscal>
12
+ <origem>%{origin}</origem>
13
+ <estoque>%{quantity}</estoque>
14
+ <gtin>%{gtin}</gtin>
15
+ <gtinEmbalagem>%{gtin_package}</gtinEmbalagem>
16
+ <largura>%{width}</largura>
17
+ <altura>%{height}</altura>
18
+ <profundidade>%{depth}</profundidade>
19
+ <estoqueMinimo>%{min_quantity}</estoqueMinimo>
20
+ <estoqueMaximo>%{max_quantity}</estoqueMaximo>
21
+ <cest>%{cest}</cest>
22
+ </produto>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <contato>
3
+ <nome>%{:name}</nome>
4
+ <fantasia>%{:company_name}</fantasia>
5
+ <tipoPessoa>%{:tax_type}</tipoPessoa>
6
+ <cpf_cnpj>%{:document}</cpf_cnpj>
7
+ <ie_rg>%{:ie_rg}</ie_rg>
8
+ <endereco>%{:address}</endereco>
9
+ <numero>%{:number}</numero>
10
+ <complemento>%{:additional_address}</complemento>
11
+ <bairro>%{:neighborhood}</bairro>
12
+ <cep>%{:zipcode}</cep>
13
+ <cidade>%{:city}</cidade>
14
+ <uf>%{:state}</uf>
15
+ <fone>%{:phone}</fone>
16
+ <email>%{:email}</email>
17
+ </contato>
@@ -0,0 +1,61 @@
1
+ require 'yaml'
2
+
3
+ module Bling
4
+ module API
5
+ class Translator
6
+
7
+ I18N_FILE ||= YAML
8
+ .load_file(File.join(File.dirname(__FILE__), 'locales/translations.yml'))
9
+ .each_with_object({}){|(k,v), result| result[k.to_sym] = v.to_sym}
10
+
11
+ class << self
12
+ def translate_url(key, id: nil)
13
+ url = pt[key.to_sym].to_s
14
+ url +="/#{id}" if id
15
+ url
16
+ end
17
+
18
+ def translate_hash(hash, to: :en)
19
+ conversion_hash = send(to)
20
+
21
+ hash.inject({}) do |result, (key, value)|
22
+ new_key = conversion_hash[underscore_symbol(key)]
23
+ new_key = underscore_symbol(key) if new_key.nil?
24
+
25
+ new_value = case value
26
+ when Hash then translate_hash(value, to: to)
27
+ when Array then value.map! { |v| translate_hash(v, to: to) }
28
+ else value
29
+ end
30
+
31
+ result[new_key] = new_value
32
+ result
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def underscore_symbol(key)
39
+ key.to_s.
40
+ gsub(/::/, '/').
41
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
42
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
43
+ tr("-", "_").
44
+ downcase.
45
+ to_sym
46
+ end
47
+
48
+ def en
49
+ I18N_FILE
50
+ end
51
+
52
+ def pt
53
+ @pt ||= I18N_FILE
54
+ .dup
55
+ .each_with_object({}) { |(key, value), result| result[value] = key }
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end