bravo 0.4.0 → 1.0.0.alpha

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.
data/lib/bravo/bill.rb CHANGED
@@ -1,59 +1,80 @@
1
1
  module Bravo
2
+ # The main class in Bravo. Handles WSFE method interactions.
3
+ # Subsequent implementations will be added here (maybe).
4
+ #
2
5
  class Bill
3
- attr_reader :client, :base_imp, :total
6
+ # Returns the Savon::Client instance in charge of the interactions with WSFE API.
7
+ # (built on init)
8
+ #
9
+ attr_reader :client
10
+
4
11
  attr_accessor :net, :doc_num, :iva_cond, :documento, :concepto, :moneda,
5
12
  :due_date, :aliciva_id, :fch_serv_desde, :fch_serv_hasta,
6
- :body, :response
13
+ :body, :response, :invoice_type
7
14
 
8
15
  def initialize(attrs = {})
9
16
  Bravo::AuthData.fetch
10
- @client = Savon::Client.new(Bravo.service_url)
11
- @body = {"Auth" => Bravo.auth_hash}
12
- @net = attrs[:net] || 0
13
- self.documento = attrs[:documento] || Bravo.default_documento
14
- self.moneda = attrs[:moneda] || Bravo.default_moneda
15
- self.iva_cond = attrs[:iva_cond]
16
- self.concepto = attrs[:concepto] || Bravo.default_concepto
17
+ @client = Savon.client(wsdl: Bravo::AuthData.wsfe_url, log: false)
18
+ @body = { "Auth" => Bravo::AuthData.auth_hash }
19
+ self.iva_cond = attrs[:iva_cond]
20
+ @net = attrs[:net] || 0
21
+ self.documento = attrs[:documento] || Bravo.default_documento
22
+ self.moneda = attrs[:moneda] || Bravo.default_moneda
23
+ self.concepto = attrs[:concepto] || Bravo.default_concepto
24
+ self.invoice_type = attrs[:invoice_type] || :invoice
17
25
  end
18
26
 
27
+ # Searches the corresponding invoice type according to the combination of
28
+ # the seller's IVA condition and the buyer's IVA condition
29
+ # @return [String] the document type string
30
+ #
19
31
  def cbte_type
20
- Bravo::BILL_TYPE[Bravo.own_iva_cond][iva_cond] ||
21
- raise(NullOrInvalidAttribute.new, "Please choose a valid document type.")
22
- end
32
+ own_iva = Bravo::BILL_TYPE.has_key?(Bravo.own_iva_cond) ? Bravo::BILL_TYPE[Bravo.own_iva_cond] : raise(NullOrInvalidAttribute.new, "Own iva_cond is invalid.")
33
+ target_iva = own_iva.has_key?(iva_cond) ? own_iva[iva_cond] : raise(NullOrInvalidAttribute.new, "Target iva_cond is invalid.")
34
+ type = target_iva.has_key?(invoice_type) ? target_iva[invoice_type] : raise(NullOrInvalidAttribute.new, "Selected invoice_type is invalid.")
23
35
 
24
- def exchange_rate
25
- return 1 if moneda == :peso
26
- response = client.fe_param_get_cotizacion do |soap|
27
- soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
28
- soap.body = body.merge!({"MonId" => Bravo::MONEDAS[moneda][:codigo]})
29
- end
30
- response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
31
36
  end
32
37
 
38
+ # Calculates the total field for the invoice by adding
39
+ # net and iva_sum.
40
+ # @return [Float] the sum of both fields, or 0 if the net is 0.
41
+ #
33
42
  def total
34
43
  @total = net.zero? ? 0 : net + iva_sum
35
44
  end
36
45
 
46
+ # Calculates the corresponding iva sum.
47
+ # This is performed by multiplying the net by the tax value
48
+ # @return [Float] the iva sum
49
+ #
50
+ # TODO: fix this
51
+ #
37
52
  def iva_sum
38
53
  @iva_sum = net * Bravo::ALIC_IVA[aliciva_id][1]
39
54
  @iva_sum.round_up_with_precision(2)
40
55
  end
41
56
 
57
+ # Files the authorization request to AFIP
58
+ # @return [Boolean] wether the request succeeded or not
59
+ #
42
60
  def authorize
43
61
  setup_bill
44
- response = client.fecae_solicitar do |soap|
45
- soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
46
- soap.body = body
62
+ response = client.call(:fecae_solicitar) do |soap|
63
+ # soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
64
+ soap.message body
47
65
  end
48
66
 
49
67
  setup_response(response.to_hash)
50
68
  self.authorized?
51
69
  end
52
70
 
71
+ # Sets up the request body for the authorisation
72
+ # @return [Hash] returns the request body as a hash
73
+ #
53
74
  def setup_bill
54
75
  today = Time.new.strftime('%Y%m%d')
55
76
 
56
- fecaereq = {"FeCAEReq" => {
77
+ fecaereq = { "FeCAEReq" => {
57
78
  "FeCabReq" => Bravo::Bill.header(cbte_type),
58
79
  "FeDetReq" => {
59
80
  "FECAEDetRequest" => {
@@ -62,14 +83,14 @@ module Bravo
62
83
  "CbteFch" => today,
63
84
  "ImpTotConc" => 0.00,
64
85
  "MonId" => Bravo::MONEDAS[moneda][:codigo],
65
- "MonCotiz" => exchange_rate,
86
+ "MonCotiz" => 1,
66
87
  "ImpOpEx" => 0.00,
67
88
  "ImpTrib" => 0.00,
68
89
  "Iva" => {
69
90
  "AlicIva" => {
70
91
  "Id" => "5",
71
92
  "BaseImp" => net,
72
- "Importe" => iva_sum}}}}}}
93
+ "Importe" => iva_sum } } } } } }
73
94
 
74
95
  detail = fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
75
96
 
@@ -77,26 +98,20 @@ module Bravo
77
98
  detail["ImpNeto"] = net.to_f
78
99
  detail["ImpIVA"] = iva_sum
79
100
  detail["ImpTotal"] = total
80
- detail["CbteDesde"] = detail["CbteHasta"] = next_bill_number
101
+ detail["CbteDesde"] = detail["CbteHasta"] = Bravo::Reference.next_bill_number(cbte_type)
81
102
 
82
103
  unless concepto == 0
83
- detail.merge!({"FchServDesde" => fch_serv_desde || today,
84
- "FchServHasta" => fch_serv_hasta || today,
85
- "FchVtoPago" => due_date || today})
104
+ detail.merge!({ "FchServDesde" => fch_serv_desde || today,
105
+ "FchServHasta" => fch_serv_hasta || today,
106
+ "FchVtoPago" => due_date || today })
86
107
  end
87
108
 
88
109
  body.merge!(fecaereq)
89
110
  end
90
111
 
91
- def next_bill_number
92
- resp = client.fe_comp_ultimo_autorizado do |s|
93
- s.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
94
- s.body = {"Auth" => Bravo.auth_hash, "PtoVta" => Bravo.sale_point, "CbteTipo" => cbte_type}
95
- end
96
-
97
- resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1
98
- end
99
-
112
+ # Returns the result of the authorization operation
113
+ # @return [Boolean] the response result
114
+ #
100
115
  def authorized?
101
116
  !response.nil? && response.header_result == "A" && response.detail_result == "A"
102
117
  end
@@ -104,11 +119,18 @@ module Bravo
104
119
  private
105
120
 
106
121
  class << self
107
- def header(cbte_type)#todo sacado de la factura
108
- {"CantReg" => "1", "CbteTipo" => cbte_type, "PtoVta" => Bravo.sale_point}
122
+ # Sets the header hash for the request
123
+ # @return [Hash]
124
+ #
125
+ def header(cbte_type)
126
+ # todo sacado de la factura
127
+ { "CantReg" => "1", "CbteTipo" => cbte_type, "PtoVta" => Bravo.sale_point }
109
128
  end
110
129
  end
111
130
 
131
+ # Response parser. Only works for the authorize method
132
+ # @return [Struct] a struct with key-value pairs with the response values
133
+ #
112
134
  def setup_response(response)
113
135
  # TODO: turn this into an all-purpose Response class
114
136
 
@@ -124,18 +146,18 @@ module Bravo
124
146
 
125
147
  request_detail.merge!(iva)
126
148
 
127
- response_hash = {:header_result => response_header.delete(:resultado),
128
- :authorized_on => response_header.delete(:fch_proceso),
129
- :detail_result => response_detail.delete(:resultado),
130
- :cae_due_date => response_detail.delete(:cae_fch_vto),
131
- :cae => response_detail.delete(:cae),
132
- :iva_id => request_detail.delete(:id),
133
- :iva_importe => request_detail.delete(:importe),
134
- :moneda => request_detail.delete(:mon_id),
135
- :cotizacion => request_detail.delete(:mon_cotiz),
136
- :iva_base_imp => request_detail.delete(:base_imp),
137
- :doc_num => request_detail.delete(:doc_nro)
138
- }.merge!(request_header).merge!(request_detail)
149
+ response_hash = { :header_result => response_header.delete(:resultado),
150
+ :authorized_on => response_header.delete(:fch_proceso),
151
+ :detail_result => response_detail.delete(:resultado),
152
+ :cae_due_date => response_detail.delete(:cae_fch_vto),
153
+ :cae => response_detail.delete(:cae),
154
+ :iva_id => request_detail.delete(:id),
155
+ :iva_importe => request_detail.delete(:importe),
156
+ :moneda => request_detail.delete(:mon_id),
157
+ :cotizacion => request_detail.delete(:mon_cotiz),
158
+ :iva_base_imp => request_detail.delete(:base_imp),
159
+ :doc_num => request_detail.delete(:doc_nro)
160
+ }.merge!(request_header).merge!(request_detail)
139
161
 
140
162
  keys, values = response_hash.to_a.transpose
141
163
  self.response = (defined?(Struct::Response) ? Struct::Response : Struct.new("Response", *keys)).new(*values)
@@ -1,5 +1,9 @@
1
1
  # encoding: utf-8
2
+ # Here we define Hashes
3
+ #
2
4
  module Bravo
5
+ # This constant contains the invoice types mappings between codes and names
6
+ # used by WSFE.
3
7
  CBTE_TIPO = {
4
8
  "01"=>"Factura A",
5
9
  "02"=>"Nota de Débito A",
@@ -21,19 +25,75 @@ module Bravo
21
25
  "64"=>"Liquidacion B"
22
26
  }
23
27
 
24
- CONCEPTOS = {"Productos"=>"01", "Servicios"=>"02", "Productos y Servicios"=>"03"}
28
+ # Name to code mapping for Sale types.
29
+ #
30
+ CONCEPTOS = { "Productos"=>"01", "Servicios"=>"02", "Productos y Servicios"=>"03" }
25
31
 
26
- DOCUMENTOS = {"CUIT"=>"80", "CUIL"=>"86", "CDI"=>"87", "LE"=>"89", "LC"=>"90", "CI Extranjera"=>"91", "en tramite"=>"92", "Acta Nacimiento"=>"93", "CI Bs. As. RNP"=>"95", "DNI"=>"96", "Pasaporte"=>"94", "Doc. (Otro)"=>"99"}
32
+ # Name to code mapping for types of documents.
33
+ #
34
+ DOCUMENTOS = {
35
+ "CUIT"=>"80",
36
+ "CUIL"=>"86",
37
+ "CDI"=>"87",
38
+ "LE"=>"89",
39
+ "LC"=>"90",
40
+ "CI Extranjera"=>"91",
41
+ "en tramite"=>"92",
42
+ "Acta Nacimiento"=>"93",
43
+ "CI Bs. As. RNP"=>"95",
44
+ "DNI"=>"96",
45
+ "Pasaporte"=>"94",
46
+ "Doc. (Otro)"=>"99" }
27
47
 
48
+ # Currency code and names hash identified by a symbol
49
+ #
28
50
  MONEDAS = {
29
- :peso => {:codigo => "PES", :nombre =>"Pesos Argentinos"},
30
- :dolar => {:codigo => "DOL", :nombre =>"Dolar Estadounidense"},
31
- :real => {:codigo => "012", :nombre =>"Real"},
32
- :euro => {:codigo => "060", :nombre =>"Euro"},
33
- :oro => {:codigo => "049", :nombre =>"Gramos de Oro Fino"}
34
- }
51
+ :peso => { :codigo => "PES", :nombre =>"Pesos Argentinos" },
52
+ :dolar => { :codigo => "DOL", :nombre =>"Dolar Estadounidense" },
53
+ :real => { :codigo => "012", :nombre =>"Real" },
54
+ :euro => { :codigo => "060", :nombre =>"Euro" },
55
+ :oro => { :codigo => "049", :nombre =>"Gramos de Oro Fino" } }
56
+
35
57
 
58
+ # Tax percentage and codes according to each iva combination
59
+ #
36
60
  ALIC_IVA = [["03", 0], ["04", 0.105], ["05", 0.21], ["06", 0.27]]
37
61
 
38
- BILL_TYPE = {:responsable_inscripto => {:responsable_inscripto => "01", :consumidor_final => "06", :exento => "06", :responsable_monotributo => "06"}}
39
- end
62
+
63
+
64
+ # This hash keeps the codes for A document types by operation
65
+ #
66
+ BILL_TYPE_A = {
67
+ :invoice => "01",
68
+ :debit => "02",
69
+ :credit => "03" }
70
+
71
+ # This hash keeps the codes for A document types by operation
72
+ #
73
+ BILL_TYPE_B = {
74
+ :invoice => "06",
75
+ :debit => "07",
76
+ :credit => "08" }
77
+
78
+ # This hash keeps the different buyer and invoice type mapping corresponding to
79
+ # the seller's iva condition and invoice kind.
80
+ # Usage:
81
+ # `BILL_TYPE[seller_iva_cond][buyer_iva_cond][invoice_type]` #=> invoice type as string
82
+ # `BILL_TYPE[:responsable_inscripto][:responsable_inscripto][:invoice]` #=> "01"
83
+ #
84
+ BILL_TYPE = {
85
+ :responsable_inscripto => {
86
+ :responsable_inscripto => BILL_TYPE_A,
87
+ :consumidor_final => BILL_TYPE_B,
88
+ :exento => BILL_TYPE_B,
89
+ :responsable_monotributo => BILL_TYPE_B } }
90
+
91
+ # This hash keeps the set of urls for wsaa and wsfe for production and testing envs
92
+ #
93
+ URLS = {
94
+ :test => { :wsaa => "https://wsaahomo.afip.gov.ar/ws/services/LoginCms",
95
+ :wsfe => "https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL" },
96
+
97
+ :production => { :wsaa => "https://wsaa.afip.gov.ar/ws/services/LoginCms",
98
+ :wsfe => "https://servicios1.afip.gov.ar/wsfev1/service.asmx" } }
99
+ end
@@ -1,7 +1,13 @@
1
+ # Float monkeypatching.
2
+ #
1
3
  class Float
4
+ # Should be removed.
5
+ #
2
6
  def round_with_precision(precision = nil)
3
7
  precision.nil? ? round : (self * (10 ** precision)).round / (10 ** precision).to_f
4
8
  end
9
+ # Should be removed.
10
+ #
5
11
  def round_up_with_precision(precision = nil)
6
12
  precision.nil? ? round : ((self * (10 ** precision)).round + 1) / (10 ** precision).to_f
7
13
  end
@@ -1,4 +1,8 @@
1
+ # Methods stolen from ActiveSupport, to avoid requiring the gem as a dependency
1
2
  class Hash
3
+ # Alters the hash, converting it's keys to symbols
4
+ # @return [Hash]
5
+ #
2
6
  def symbolize_keys!
3
7
  keys.each do |key|
4
8
  self[(key.to_sym rescue key) || key] = delete(key)
@@ -6,10 +10,16 @@ class Hash
6
10
  self
7
11
  end unless method_defined?(:symbolize_keys!)
8
12
 
13
+ # Returns a copy of the hash, with it's keys converted to symbols
14
+ # @return [Hash]
15
+ #
9
16
  def symbolize_keys
10
17
  dup.symbolize_keys!
11
18
  end unless method_defined?(:symbolize_keys)
12
19
 
20
+ # Alters the hash, converting its keys to underscore strings
21
+ # @return [Hash]
22
+ #
13
23
  def underscore_keys!
14
24
  keys.each do |key|
15
25
  self[(key.underscore rescue key) || key] = delete(key)
@@ -17,6 +27,8 @@ class Hash
17
27
  self
18
28
  end unless method_defined?(:underscore_keys!)
19
29
 
30
+ # Returns a copy of the hash, with it's keys converted to underscore strings
31
+ # @return [Hash]
20
32
  def underscore_keys
21
33
  dup.underscore_keys!
22
34
  end unless method_defined?(:underscore_keys)
@@ -1,5 +1,8 @@
1
- # Stolen from activesupport/lib/active_support/inflector/methods.rb, line 48
1
+ # Added to avoid requiring ActiveSupport as dependency
2
+ #
2
3
  class String
4
+ # Stolen from activesupport/lib/active_support/inflector/methods.rb, line 48
5
+ #
3
6
  def underscore
4
7
  word = self.to_s.dup
5
8
  word.gsub!(/::/, '/')
@@ -0,0 +1,37 @@
1
+ module Bravo
2
+ # Class in charge of issuing read requests on the api
3
+ #
4
+ class Reference
5
+ # Fetches the number for the next bill to be issued
6
+ # @return [Integer] the number for the next bill
7
+ #
8
+ def self.next_bill_number(cbte_type)
9
+ set_client
10
+ resp = @client.call(:fe_comp_ultimo_autorizado) do |soap|
11
+ # soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
12
+ soap.message "Auth" => Bravo::AuthData.auth_hash, "PtoVta" => Bravo.sale_point, "CbteTipo" => cbte_type
13
+ end
14
+
15
+ resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1
16
+ end
17
+
18
+ # Fetches the possible document codes and names
19
+ # @return [Hash]
20
+ #
21
+ def self.get_custom(operation)
22
+ set_client
23
+ resp = @client.call(operation) do |soap|
24
+ soap.message "Auth" => Bravo::AuthData.auth_hash
25
+ end
26
+ resp.to_hash
27
+ end
28
+
29
+ # Sets up the cliet to perform consults to the api
30
+ #
31
+ #
32
+ def self.set_client
33
+ Bravo::AuthData.fetch
34
+ @client = Savon.client(wsdl: Bravo::AuthData.wsfe_url, log: false)
35
+ end
36
+ end
37
+ end
data/lib/bravo/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module Bravo
2
- VERSION = "0.4.0"
2
+ # Gem version
3
+ #
4
+ VERSION = "1.0.0.alpha"
3
5
  end
data/lib/bravo/wsaa.rb ADDED
@@ -0,0 +1,96 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Bravo
3
+ # Authorization class. Handles interactions wiht the WSAA, to provide
4
+ # valid key and signature that will last for a day.
5
+ #
6
+ class Wsaa
7
+ # Main method for authentication and authorization.
8
+ # When successful, produces the yaml file with auth data.
9
+ #
10
+ def self.login
11
+ tra = build_tra
12
+ cms = build_cms(tra)
13
+ req = build_request(cms)
14
+ auth = call_wsaa(req)
15
+
16
+ write_yaml(auth)
17
+ end
18
+
19
+ protected
20
+ # Builds the xml for the "Ticket de Requerimiento de Acceso"
21
+ # @return [String] containing the request body
22
+ #
23
+ def self.build_tra
24
+ now = Time.now
25
+ from = now.strftime("%FT%T%:z")
26
+ to = ((now - 120) + (24*60*60)).strftime("%FT%T%:z") # make sure ti will last for 24hs - 2 mins
27
+ id = now.strftime("%s")
28
+ tra = <<-EOF
29
+ <?xml version="1.0" encoding="UTF-8"?>
30
+ <loginTicketRequest version="1.0">
31
+ <header>
32
+ <uniqueId>#{ id }</uniqueId>
33
+ <generationTime>#{ from }</generationTime>
34
+ <expirationTime>#{ to }</expirationTime>
35
+ </header>
36
+ <service>wsfe</service>
37
+ </loginTicketRequest>
38
+ EOF
39
+ return tra
40
+ end
41
+
42
+ # Builds the CMS
43
+ # @return [String] cms
44
+ #
45
+ def self.build_cms(tra)
46
+ cms = `echo '#{ tra }' |
47
+ #{ Bravo.openssl_bin } cms -sign -in /dev/stdin -signer #{ Bravo.cert } -inkey #{ Bravo.pkey } -nodetach \
48
+ -outform der |
49
+ #{ Bravo.openssl_bin } base64 -e`
50
+ return cms
51
+ end
52
+
53
+ # Builds the CMS request to log in to the server
54
+ # @return [String] the cms body
55
+ #
56
+ def self.build_request(cms)
57
+ request = <<-XML
58
+ <?xml version="1.0" encoding="UTF-8"?>
59
+ <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://wsaa.view.sua.dvadac.desein.afip.gov">
60
+ <SOAP-ENV:Body>
61
+ <ns1:loginCms>
62
+ <ns1:in0>
63
+ #{ cms }
64
+ </ns1:in0>
65
+ </ns1:loginCms>
66
+ </SOAP-ENV:Body>
67
+ </SOAP-ENV:Envelope>
68
+ XML
69
+ return request
70
+ end
71
+
72
+ # Calls the WSAA with the request built by build_request
73
+ # @return [Array] with the token and signature
74
+ #
75
+ def self.call_wsaa(req)
76
+ response = `echo '#{ req }' |
77
+ curl -k -s -H 'Content-Type: application/soap+xml; action=""' -d @- #{ Bravo::AuthData.wsaa_url }`
78
+
79
+ response = CGI::unescapeHTML(response)
80
+ token = response.scan(/\<token\>(.+)\<\/token\>/).first.first
81
+ sign = response.scan(/\<sign\>(.+)\<\/sign\>/).first.first
82
+ return [token, sign]
83
+ end
84
+
85
+ # Writes the token and signature to a YAML file in the /tmp directory
86
+ #
87
+ def self.write_yaml(certs)
88
+ yml = <<-YML
89
+ token: #{certs[0]}
90
+ sign: #{certs[1]}
91
+ YML
92
+ `echo '#{ yml }' > /tmp/bravo_#{ Bravo.cuit }_#{ Time.new.strftime('%d_%m_%Y') }.yml`
93
+ end
94
+
95
+ end
96
+ end
data/lib/bravo.rb CHANGED
@@ -5,23 +5,28 @@ require "savon"
5
5
  require "bravo/core_ext/float"
6
6
  require "bravo/core_ext/hash"
7
7
  require "bravo/core_ext/string"
8
+
8
9
  module Bravo
9
10
 
11
+ # Exception Class for missing or invalid attributes
12
+ #
10
13
  class NullOrInvalidAttribute < StandardError; end
11
14
 
15
+ # Exception Clas for missing or invalid certifficate
16
+ #
17
+ class MissingCertificate < StandardError; end
18
+
12
19
  autoload :Authorizer, "bravo/authorizer"
13
20
  autoload :AuthData, "bravo/auth_data"
14
21
  autoload :Bill, "bravo/bill"
15
22
  autoload :Constants, "bravo/constants"
16
-
23
+ autoload :Wsaa, "bravo/wsaa"
24
+ autoload :Reference, "bravo/reference"
17
25
 
18
26
  extend self
19
- attr_accessor :cuit, :sale_point, :service_url, :default_documento, :pkey, :cert,
20
- :default_concepto, :default_moneda, :own_iva_cond, :verbose, :auth_url
21
27
 
22
- def auth_hash
23
- {"Token" => Bravo::TOKEN, "Sign" => Bravo::SIGN, "Cuit" => Bravo.cuit}
24
- end
28
+ attr_accessor :cuit, :sale_point, :default_documento, :pkey, :cert,
29
+ :default_concepto, :default_moneda, :own_iva_cond,
30
+ :verbose, :openssl_bin
25
31
 
26
- Savon::Request.log = false unless (Bravo.verbose == "true") || (ENV["VERBOSE"] == true)
27
- end
32
+ end
@@ -1,12 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe "AuthData" do
4
- it "should create constants for todays data" do
5
- Bravo::AuthData.fetch
6
- if RUBY_VERSION >= "1.9"
4
+ describe ".fetch" do
5
+ it "creates constants for todays data" do
6
+ Bravo.constants.should_not include(:TOKEN, :SIGN)
7
+
8
+ Bravo::AuthData.fetch
9
+
7
10
  Bravo.constants.should include(:TOKEN, :SIGN)
8
- else
9
- Bravo.constants.should include("TOKEN", "SIGN")
10
11
  end
11
12
  end
12
- end
13
+ end