afipws 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.
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>