afipws 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +69 -0
  6. data/README.rdoc +32 -0
  7. data/Rakefile +7 -0
  8. data/afipws.gemspec +29 -0
  9. data/autotest/discover.rb +1 -0
  10. data/lib/afipws.rb +23 -0
  11. data/lib/afipws/client.rb +48 -0
  12. data/lib/afipws/excepciones.rb +13 -0
  13. data/lib/afipws/type_conversions.rb +38 -0
  14. data/lib/afipws/version.rb +3 -0
  15. data/lib/afipws/wsaa.rb +77 -0
  16. data/lib/afipws/wsfe.rb +88 -0
  17. data/lib/core_ext/hash.rb +21 -0
  18. data/lib/core_ext/string.rb +9 -0
  19. data/spec/afipws/test.crt +17 -0
  20. data/spec/afipws/test.key +15 -0
  21. data/spec/afipws/type_conversions_spec.rb +30 -0
  22. data/spec/afipws/wsaa_spec.rb +68 -0
  23. data/spec/afipws/wsfe_spec.rb +163 -0
  24. data/spec/core_ext/hash_spec.rb +44 -0
  25. data/spec/fixtures/fe_comp_consultar/success.xml +41 -0
  26. data/spec/fixtures/fe_comp_tot_x_request/success.xml +9 -0
  27. data/spec/fixtures/fe_comp_ultimo_autorizado/success.xml +11 -0
  28. data/spec/fixtures/fe_dummy/success.xml +11 -0
  29. data/spec/fixtures/fe_param_get_cotizacion/dolar.xml +13 -0
  30. data/spec/fixtures/fe_param_get_cotizacion/inexistente.xml +14 -0
  31. data/spec/fixtures/fe_param_get_tipos_cbte/failure_1_error.xml +14 -0
  32. data/spec/fixtures/fe_param_get_tipos_cbte/failure_2_errors.xml +18 -0
  33. data/spec/fixtures/fe_param_get_tipos_cbte/success.xml +22 -0
  34. data/spec/fixtures/fe_param_get_tipos_doc/success.xml +16 -0
  35. data/spec/fixtures/fe_param_get_tipos_iva/success.xml +16 -0
  36. data/spec/fixtures/fe_param_get_tipos_monedas/success.xml +22 -0
  37. data/spec/fixtures/fe_param_get_tipos_tributos/success.xml +16 -0
  38. data/spec/fixtures/fecae_solicitar/autorizacion_1_cbte.xml +30 -0
  39. data/spec/fixtures/fecae_solicitar/autorizacion_2_cbtes.xml +41 -0
  40. data/spec/fixtures/fecae_solicitar/observaciones.xml +40 -0
  41. data/spec/fixtures/login_cms/fault.xml +12 -0
  42. data/spec/fixtures/login_cms/success.xml +16 -0
  43. data/spec/fixtures/login_cms/token_expirado.xml +14 -0
  44. data/spec/fixtures/wsaa.wsdl +103 -0
  45. data/spec/fixtures/wsfe.wsdl +1372 -0
  46. data/spec/manual/autorizar_comprobante.rb +22 -0
  47. data/spec/manual/generar_keys.txt +8 -0
  48. data/spec/manual/obtener_ta.rb +18 -0
  49. data/spec/spec_helper.rb +12 -0
  50. data/spec/support/matchers.rb +37 -0
  51. metadata +237 -0
@@ -0,0 +1,21 @@
1
+ class Hash
2
+ def fetch_path path
3
+ path.split('/').drop(1).inject(self) do |hash, key|
4
+ if scan = key.scan(/\[[\d+]\]/).first
5
+ key.sub! scan, ''
6
+ idx = scan.scan(/\d+/).first.to_i
7
+ hash.respond_to?(:has_key?) && hash.has_key?(key) ? hash[key][idx] : break
8
+ else
9
+ hash.respond_to?(:has_key?) && hash.has_key?(key) ? hash[key] : break
10
+ end
11
+ end
12
+ end
13
+
14
+ def select_keys *keys
15
+ select { |k, _| keys.include? k }
16
+ end
17
+
18
+ def has_entries? entries
19
+ entries.each_pair.all? { |k, v| self[k] == v }
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ class String
2
+ def camelize first_letter_in_uppercase = true
3
+ if first_letter_in_uppercase
4
+ gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
5
+ else
6
+ to_s[0].chr.downcase + self.camelize[1..-1]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICsDCCAhmgAwIBAgIJAPAqRSXBMKn4MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
3
+ BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
4
+ aWRnaXRzIFB0eSBMdGQwHhcNMTEwMTE1MTc1ODUxWhcNMTQwMTE0MTc1ODUxWjBF
5
+ MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
6
+ ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
7
+ gQDDuCVJOzIXS72s1Os3s8Q3y4jFdKDuBbwzuoaoT68WTRpinxvZRfwPiher9RaL
8
+ gHQFumu4UnYlxi8jxo8A8X8HTzi6fbDWww8xsJudAWwYndKUY8wsT/4Gt91R/PYR
9
+ Ex2LQ6erM/9F6hAGk9FWUIQpkL4HjcEF355FOEHa8a5hawIDAQABo4GnMIGkMB0G
10
+ A1UdDgQWBBS/2vV+khMBLdpiTDFvb81e163iajB1BgNVHSMEbjBsgBS/2vV+khMB
11
+ LdpiTDFvb81e163iaqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
12
+ U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPAqRSXB
13
+ MKn4MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAPgexomZ+OpQFwtPZ
14
+ p2X7kxlmw6YsAiKO9ogYDeGgMQKr5wNym6bIPyNMJBMKwBdndeh/Db9gtqWjevqp
15
+ 4I+oaYsWf4D5WhjuLCIXgOSLRWSiRmtzm+CjwMmy7DJtbfAcsQtc7x0q+1oOsvp8
16
+ o8xrGC/7ueELg2ZEoBNImTF201o=
17
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQDDuCVJOzIXS72s1Os3s8Q3y4jFdKDuBbwzuoaoT68WTRpinxvZ
3
+ RfwPiher9RaLgHQFumu4UnYlxi8jxo8A8X8HTzi6fbDWww8xsJudAWwYndKUY8ws
4
+ T/4Gt91R/PYREx2LQ6erM/9F6hAGk9FWUIQpkL4HjcEF355FOEHa8a5hawIDAQAB
5
+ AoGBAJGDFk2k8i/5wvJ9dsf6IldtPqm3dXKh1vQKqNT4MW9+MbDDJLxcWPPgsorJ
6
+ dFKRVTFxEWd//5FEEIYjuOx1n/+qnQsLOwbXKvmKTYxpDaCHVjNiCpVbhGRzkwDt
7
+ 4vyd6WvqCYWRsYq9Jb/uFwrIDnsNXiISXervlj2ZFYxrAGiRAkEA/qN4Apw5RqCJ
8
+ W3QXU6GHyHjGW/spGyQ2myXJo4OGPR+cT5WjzGyIOaNqypgG9ZSS5qFQ8OdDSxCZ
9
+ EB9UXzunswJBAMTECEqjdGTI+u3O5k01DN/tsKDFOHMgpa+95y3S+J5HT7VN26dR
10
+ sckIA/fM7n9lqRtUQY0tle9B0zqYuMQCg2kCQQD4WxfB8/0pFYri1+eoefOlY6aU
11
+ L/N3tWpNCB4SjUVweFRMivane3OiQ/D0iDLBc5eTueLoE6den2Gqh+QSvmxhAkA6
12
+ YL7lBiHeVRK9w4jolzi+p1KkIF9jKOh/f6Q7IEDLFPU9IWBt//rzXgFvX8nS2mKV
13
+ zSW1sTSuy6TT2cPXw7chAkEAm3yA3fgbMLPCKdTNduIoA0xxACElyvDH/0kqUf8Z
14
+ 90XGCsLnF6KHsDtaBGA8aYY1UzOWnhxSXTFb00v2/FP2nw==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Afipws::TypeConversions do
5
+ include Afipws::TypeConversions
6
+
7
+ context "r2x" do
8
+ it "debería convertir values de hashes a xml types" do
9
+ r2x({fecha: Date.new(2011, 1, 2), :id => 1}, fecha: :date).should == {fecha: '20110102', id: 1}
10
+ r2x({container: {fecha: Date.new(2011, 1, 2)}}, fecha: :date).should == {container: {fecha: '20110102'}}
11
+ end
12
+
13
+ it "debería convertir values de hashes aunque estén en arrays" do
14
+ r2x([{fecha: Date.new(2011, 1, 2)}], fecha: :date).should == [{fecha: '20110102'}]
15
+ r2x({container: [{fecha: Date.new(2011, 1, 2)}, {fecha: Date.new(2011, 1, 3)}]}, fecha: :date).should == {container: [{fecha: '20110102'}, {fecha: '20110103'}]}
16
+ end
17
+ end
18
+
19
+ context "x2r" do
20
+ it "deberia convertir values de hashes de xml types a ruby" do
21
+ x2r({fecha: '20110102', id: '1', total: '1.23', obs: 'algo'}, fecha: :date, id: :integer, total: :float)
22
+ .should == {fecha: Date.new(2011,1,2), id: 1, total: 1.23, obs: 'algo'}
23
+ x2r({container: {id: '1'}}, id: :integer).should == {container: {id: 1}}
24
+ end
25
+
26
+ it "debería hacer la conversión en arrays también" do
27
+ x2r({container: [{id: '1'}, {id: '2'}]}, id: :integer).should == {container: [{id: 1}, {id: 2}]}
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,68 @@
1
+ # coding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Afipws::WSAA do
5
+ context "generación documento tra" do
6
+ it "debería generar xml" do
7
+ Time.stubs(:now).returns Time.local(2001, 12, 31, 12, 00)
8
+ xml = subject.generar_tra 'wsfe', 2400
9
+ xml.should match_xpath "/loginTicketRequest/header/uniqueId", Time.now.to_i.to_s
10
+ xml.should match_xpath "/loginTicketRequest/header/generationTime", "2001-12-31T11:20:00-03:00"
11
+ xml.should match_xpath "/loginTicketRequest/header/expirationTime", "2001-12-31T12:40:00-03:00"
12
+ xml.should match_xpath "/loginTicketRequest/service", "wsfe"
13
+ end
14
+ end
15
+
16
+ context "firmado del tra" do
17
+ it "debería firmar el tra usando el certificado y la clave privada" do
18
+ key = File.read(File.dirname(__FILE__) + '/test.key')
19
+ crt = File.read(File.dirname(__FILE__) + '/test.crt')
20
+ tra = subject.generar_tra 'wsfe', 2400
21
+ subject.firmar_tra(tra, key, crt).to_s.should =~ /BEGIN PKCS7/
22
+ end
23
+ end
24
+
25
+ context "codificación del tra" do
26
+ it "debería quitarle el header y footer" do
27
+ subject.codificar_tra(OpenSSL::PKCS7.new).should == "MAMGAQA=\n"
28
+ end
29
+ end
30
+
31
+ context "login" do
32
+ it "debería mandar el TRA al WS y obtener el TA" do
33
+ ws = Afipws::WSAA.new :key => 'key', :cert => 'cert'
34
+ ws.expects(:tra).with('key', 'cert', 'wsfe', 2400).returns('tra')
35
+ savon.expects('loginCms').with('wsdl:in0' => 'tra').returns(:success)
36
+ ta = ws.login
37
+ ta[:token].should == 'PD94='
38
+ ta[:sign].should == 'i9xDN='
39
+ ta[:generation_time].should == Time.local(2011,01,12,18,57,04)
40
+ ta[:expiration_time].should == Time.local(2011,01,13,06,57,04)
41
+ end
42
+
43
+ it "debería encapsular SOAP Faults" do
44
+ subject.stubs(:tra).returns('')
45
+ savon.stubs('loginCms').returns(:fault)
46
+ expect { subject.login }.to raise_error Afipws::WSError, /CMS no es valido/
47
+ end
48
+ end
49
+
50
+ context "auth" do
51
+ before { Time.stubs(:now).returns(now = Time.local(2010,1,1)) }
52
+
53
+ it "debería cachear TA" do
54
+ subject.expects(:login).once.returns(ta = {token: 'token', sign: 'sign', expiration_time: Time.now + 60})
55
+ subject.auth
56
+ subject.auth
57
+ subject.ta.should equal ta
58
+ end
59
+
60
+ it "si el TA expiró debería ejecutar solicitar uno nuevo" do
61
+ subject.expects(:login).twice.returns(token: 't1', expiration_time: Time.now - 2).then.returns(token: 't2')
62
+ subject.auth
63
+ subject.ta[:token].should == 't1'
64
+ subject.auth
65
+ subject.ta[:token].should == 't2'
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,163 @@
1
+ # coding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Afipws::WSFE do
5
+ let :ws do
6
+ wsaa = Afipws::WSAA.new
7
+ wsaa.stubs :login => { :token => 't', :sign => 's' }
8
+ Afipws::WSFE.new :cuit => '1', :wsaa => wsaa
9
+ end
10
+
11
+ context "Métodos de negocio" do
12
+ it "dummy" do
13
+ savon.expects('FEDummy').returns(:success)
14
+ ws.dummy.should == { :app_server => "OK", :db_server => "OK", :auth_server => "OK" }
15
+ end
16
+
17
+ it "tipos_comprobantes" do
18
+ savon.expects('FEParamGetTiposCbte').returns(:success)
19
+ ws.tipos_comprobantes.should == [
20
+ { :id => 1, :desc => "Factura A", :fch_desde => Date.new(2010,9,17), :fch_hasta => nil },
21
+ { :id => 2, :desc => "Nota de Débito A", :fch_desde => Date.new(2010,9,18), :fch_hasta => Date.new(2011,9,18) }]
22
+ end
23
+
24
+ it "tipos_documentos" do
25
+ savon.expects('FEParamGetTiposDoc').returns(:success)
26
+ ws.tipos_documentos.should == [{ :id => 80, :desc => "CUIT", :fch_desde => Date.new(2008,7,25), :fch_hasta => nil }]
27
+ end
28
+
29
+ it "tipos_monedas" do
30
+ savon.expects('FEParamGetTiposMonedas').returns(:success)
31
+ ws.tipos_monedas.should == [
32
+ { :id => 'PES', :desc => "Pesos Argentinos", :fch_desde => Date.new(2009,4,3), :fch_hasta => nil },
33
+ { :id => '002', :desc => "Dólar Libre EEUU", :fch_desde => Date.new(2009,4,16), :fch_hasta => nil }]
34
+ end
35
+
36
+ it "tipos_iva" do
37
+ savon.expects('FEParamGetTiposIva').returns(:success)
38
+ ws.tipos_iva.should == [{ :id => 5, :desc => "21%", :fch_desde => Date.new(2009,2,20), :fch_hasta => nil }]
39
+ end
40
+
41
+ it "tipos_tributos" do
42
+ savon.expects('FEParamGetTiposTributos').returns(:success)
43
+ ws.tipos_tributos.should == [{ :id => 2, :desc => "Impuestos provinciales", :fch_desde => Date.new(2010,9,17), :fch_hasta => nil }]
44
+ end
45
+
46
+ context "cotizacion" do
47
+ it "cuando la moneda solicitada existe" do
48
+ savon.expects('FEParamGetCotizacion').with(has_path '/MonId' => 'DOL').returns(:dolar)
49
+ ws.cotizacion('DOL').should == 3.976
50
+ end
51
+
52
+ it "cuando la moneda no existe" do
53
+ savon.expects('FEParamGetCotizacion').with(has_path '/MonId' => 'PES').returns(:inexistente)
54
+ expect { ws.cotizacion('PES') }.to raise_error Afipws::WSError, /602: Sin Resultados/
55
+ end
56
+ end
57
+
58
+ it "cant_max_registros_x_request" do
59
+ savon.expects('FECompTotXRequest').returns(:success)
60
+ ws.cant_max_registros_x_request.should == 250
61
+ end
62
+
63
+ context "autorizar_comprobante" do
64
+ it "debería devolver un hash con el CAE y su fecha de vencimiento" do
65
+ savon.expects('FECAESolicitar').with(has_path '/FeCAEReq/FeCabReq/CantReg' => 1,
66
+ '/FeCAEReq/FeCabReq/PtoVta' => 2,
67
+ '/FeCAEReq/FeCabReq/CbteTipo' => 1,
68
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/DocTipo' => 80,
69
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/DocNro' => 30521189203,
70
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/CbteFch' => '20110113',
71
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/ImpTotal' => 1270.48,
72
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/ImpIVA' => 220.5,
73
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[0]/Id' => 5,
74
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[0]/Importe' => 220.5
75
+ ).returns(:autorizacion_1_cbte)
76
+ rta = ws.autorizar_comprobantes(:cbte_tipo => 1, :pto_vta => 2, :comprobantes => [{:cbte_nro => 1, :concepto => 1,
77
+ :doc_nro => 30521189203, :doc_tipo => 80, :cbte_fch => Date.new(2011,01,13),
78
+ :imp_total => 1270.48, :imp_neto => 1049.98, :imp_iva => 220.50, :mon_id => 'PES', :mon_cotiz => 1,
79
+ :iva => { :alic_iva => [{ :id => 5, :base_imp => 1049.98, :importe => 220.50 }]}
80
+ }])
81
+ rta[0].should have_entries :cae => '61023008595705', :cae_fch_vto => Date.new(2011,01,23), :cbte_nro => 1
82
+ rta.should have(1).item
83
+ end
84
+
85
+ it "con varias alicuotas iva" do
86
+ savon.expects('FECAESolicitar').with(has_path({
87
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[0]/Id' => 5,
88
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[0]/Importe' => 21,
89
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[1]/Id' => 4,
90
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/Iva/AlicIva[1]/Importe' => 5.25
91
+ })).returns(:autorizacion_1_cbte)
92
+ ws.autorizar_comprobantes(:cbte_tipo => 1, :pto_vta => 2, :comprobantes => [{:iva => {:alic_iva => [
93
+ { :id => 5, :base_imp => 100, :importe => 21 },
94
+ { :id => 4, :base_imp => 50, :importe => 5.25 }
95
+ ]}}])
96
+ end
97
+
98
+ it "con varios comprobantes aprobados" do
99
+ savon.expects('FECAESolicitar').with(has_path({
100
+ '/FeCAEReq/FeCabReq/CantReg' => 2,
101
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[0]/CbteDesde' => 5,
102
+ '/FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteDesde' => 6,
103
+ })).returns(:autorizacion_2_cbtes)
104
+ rta = ws.autorizar_comprobantes(:cbte_tipo => 1, :pto_vta => 2, :comprobantes => [
105
+ { :cbte_nro => 5 }, { :cbte_nro => 6 }
106
+ ])
107
+ rta[0].should have_entries :cbte_nro => 5, :cae => '61033008894096'
108
+ rta[1].should have_entries :cbte_nro => 6, :cae => '61033008894101'
109
+ end
110
+
111
+ it "con observaciones" do
112
+ savon.stubs('FECAESolicitar').returns(:observaciones)
113
+ rta = ws.autorizar_comprobantes :comprobantes => []
114
+ rta[0].should have_entries :cbte_nro => 3, :cae => nil, :observaciones => [
115
+ {:code => 10048, :msg => 'Msg 1'}, {:code => 10018, :msg => 'Msg 2'}]
116
+ end
117
+ end
118
+
119
+ it "ultimo_comprobante_autorizado" do
120
+ savon.expects('FECompUltimoAutorizado').with(has_path '/PtoVta' => 1, '/CbteTipo' => 1).returns(:success)
121
+ ws.ultimo_comprobante_autorizado(:pto_vta => 1, :cbte_tipo => 1).should == 20
122
+ end
123
+
124
+ it "consultar_comprobante" do
125
+ savon.expects('FECompConsultar').with(has_entries 'wsdl:PtoVta' => 1, 'wsdl:CbteTipo' => 2, 'wsdl:CbteNro' => 3).returns(:success)
126
+ rta = ws.consultar_comprobante(:pto_vta => 1, :cbte_tipo => 2, :cbte_nro => 3)
127
+ rta[:cod_autorizacion].should == '61023008595705'
128
+ rta[:emision_tipo].should == 'CAE'
129
+ end
130
+ end
131
+
132
+ context "autenticacion" do
133
+ it "debería autenticarse usando el WSAA" do
134
+ wsfe = Afipws::WSFE.new :cuit => '1', :cert => 'cert', :key => 'key'
135
+ wsfe.wsaa.cert.should == 'cert'
136
+ wsfe.wsaa.key.should == 'key'
137
+ wsfe.wsaa.service.should == 'wsfe'
138
+ wsfe.wsaa.expects(:login).returns({ :token => 't', :sign => 's' })
139
+ savon.expects('FEParamGetTiposCbte').with('wsdl:Auth' => {'wsdl:Token' => 't', 'wsdl:Sign' => 's', 'wsdl:Cuit' => '1'}).returns(:success)
140
+ wsfe.tipos_comprobantes
141
+ end
142
+ end
143
+
144
+ context "manejo de errores" do
145
+ it "cuando hay un error" do
146
+ savon.expects('FEParamGetTiposCbte').returns(:failure_1_error)
147
+ expect { ws.tipos_comprobantes }.to raise_error { |e|
148
+ e.should be_a Afipws::WSError
149
+ e.errors.should == [{ :code => "600", :msg => "No se corresponden token con firma" }]
150
+ e.message.should == "600: No se corresponden token con firma"
151
+ }
152
+ end
153
+
154
+ it "cuando hay varios errores" do
155
+ savon.expects('FEParamGetTiposCbte').returns(:failure_2_errors)
156
+ expect { ws.tipos_comprobantes }.to raise_error { |e|
157
+ e.should be_a Afipws::WSError
158
+ e.errors.should == [{ :code => "600", :msg => "No se corresponden token con firma" }, { :code => "601", :msg => "CUIT representada no incluida en token" }]
159
+ e.message.should == "600: No se corresponden token con firma; 601: CUIT representada no incluida en token"
160
+ }
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Hash do
5
+ context "fetch_path" do
6
+ it "deberia aceptar un path como /../.. y retornar el value" do
7
+ hash = { '1' => 2, '3' => { '4' => '5', '6' => { '7' => '8' } } }
8
+ hash.fetch_path('/1').should == 2
9
+ hash.fetch_path('/1/2').should == nil
10
+ hash.fetch_path('/2').should == nil
11
+ hash.fetch_path('/3/4').should == '5'
12
+ hash.fetch_path('/3/6').should == { '7' => '8' }
13
+ hash.fetch_path('/3/6/7').should == '8'
14
+ end
15
+
16
+ it "debería permitir acceder a values tipo array con subindice" do
17
+ hash = { '1' => [{ '2' => 3 }, { '4' => 5 }] }
18
+ hash.fetch_path('/1[0]/2').should == 3
19
+ hash.fetch_path('/1[1]/4').should == 5
20
+ hash.fetch_path('/1[0]').should == { '2' => 3 }
21
+ hash.fetch_path('/1[2]').should == nil
22
+ end
23
+ end
24
+
25
+ context "select_keys" do
26
+ it "debería tomar los values de las keys indicadas" do
27
+ hash = Hash[1, 2, 3, 4]
28
+ hash.select_keys(1).should == {1 => 2}
29
+ hash.select_keys(1, 3).should == {1 => 2, 3 => 4}
30
+ hash.select_keys(5).should == {}
31
+ hash.select_keys(5, 3).should == {3 => 4}
32
+ end
33
+ end
34
+
35
+ context "has_entries?" do
36
+ subject { Hash[1, 2, 3, 4] }
37
+
38
+ it "debería devolver true cuando self incluye todas las entries del hash parametro" do
39
+ should have_entries 1 => 2
40
+ should have_entries 3 => 4, 1 => 2
41
+ should_not have_entries 1 => 3
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
+ <soap:Body>
3
+ <FECompConsultarResponse xmlns="http://ar.gov.afip.dif.FEV1/">
4
+ <FECompConsultarResult>
5
+ <ResultGet>
6
+ <Concepto>1</Concepto>
7
+ <DocTipo>80</DocTipo>
8
+ <DocNro>30521189203</DocNro>
9
+ <CbteDesde>1</CbteDesde>
10
+ <CbteHasta>1</CbteHasta>
11
+ <CbteFch>20110113</CbteFch>
12
+ <ImpTotal>1270.48</ImpTotal>
13
+ <ImpTotConc>0</ImpTotConc>
14
+ <ImpNeto>1049.98</ImpNeto>
15
+ <ImpOpEx>0</ImpOpEx>
16
+ <ImpTrib>0</ImpTrib>
17
+ <ImpIVA>220.5</ImpIVA>
18
+ <FchServDesde/>
19
+ <FchServHasta/>
20
+ <FchVtoPago/>
21
+ <MonId>PES</MonId>
22
+ <MonCotiz>1</MonCotiz>
23
+ <Iva>
24
+ <AlicIva>
25
+ <Id>5</Id>
26
+ <BaseImp>1049.98</BaseImp>
27
+ <Importe>220.5</Importe>
28
+ </AlicIva>
29
+ </Iva>
30
+ <Resultado>A</Resultado>
31
+ <CodAutorizacion>61023008595705</CodAutorizacion>
32
+ <EmisionTipo>CAE</EmisionTipo>
33
+ <FchVto>20110123</FchVto>
34
+ <FchProceso>20110113165500</FchProceso>
35
+ <PtoVta>1</PtoVta>
36
+ <CbteTipo>1</CbteTipo>
37
+ </ResultGet>
38
+ </FECompConsultarResult>
39
+ </FECompConsultarResponse>
40
+ </soap:Body>
41
+ </soap:Envelope>
@@ -0,0 +1,9 @@
1
+ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
+ <soap:Body>
3
+ <FECompTotXRequestResponse xmlns="http://ar.gov.afip.dif.FEV1/">
4
+ <FECompTotXRequestResult>
5
+ <RegXReq>250</RegXReq>
6
+ </FECompTotXRequestResult>
7
+ </FECompTotXRequestResponse>
8
+ </soap:Body>
9
+ </soap:Envelope>
@@ -0,0 +1,11 @@
1
+ <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
+ <soap:Body>
3
+ <FECompUltimoAutorizadoResponse xmlns="http://ar.gov.afip.dif.FEV1/">
4
+ <FECompUltimoAutorizadoResult>
5
+ <PtoVta>1</PtoVta>
6
+ <CbteTipo>1</CbteTipo>
7
+ <CbteNro>20</CbteNro>
8
+ </FECompUltimoAutorizadoResult>
9
+ </FECompUltimoAutorizadoResponse>
10
+ </soap:Body>
11
+ </soap:Envelope>