bling-ruby-api 0.0.1

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,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