afipws 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +69 -0
- data/README.rdoc +32 -0
- data/Rakefile +7 -0
- data/afipws.gemspec +29 -0
- data/autotest/discover.rb +1 -0
- data/lib/afipws.rb +23 -0
- data/lib/afipws/client.rb +48 -0
- data/lib/afipws/excepciones.rb +13 -0
- data/lib/afipws/type_conversions.rb +38 -0
- data/lib/afipws/version.rb +3 -0
- data/lib/afipws/wsaa.rb +77 -0
- data/lib/afipws/wsfe.rb +88 -0
- data/lib/core_ext/hash.rb +21 -0
- data/lib/core_ext/string.rb +9 -0
- data/spec/afipws/test.crt +17 -0
- data/spec/afipws/test.key +15 -0
- data/spec/afipws/type_conversions_spec.rb +30 -0
- data/spec/afipws/wsaa_spec.rb +68 -0
- data/spec/afipws/wsfe_spec.rb +163 -0
- data/spec/core_ext/hash_spec.rb +44 -0
- data/spec/fixtures/fe_comp_consultar/success.xml +41 -0
- data/spec/fixtures/fe_comp_tot_x_request/success.xml +9 -0
- data/spec/fixtures/fe_comp_ultimo_autorizado/success.xml +11 -0
- data/spec/fixtures/fe_dummy/success.xml +11 -0
- data/spec/fixtures/fe_param_get_cotizacion/dolar.xml +13 -0
- data/spec/fixtures/fe_param_get_cotizacion/inexistente.xml +14 -0
- data/spec/fixtures/fe_param_get_tipos_cbte/failure_1_error.xml +14 -0
- data/spec/fixtures/fe_param_get_tipos_cbte/failure_2_errors.xml +18 -0
- data/spec/fixtures/fe_param_get_tipos_cbte/success.xml +22 -0
- data/spec/fixtures/fe_param_get_tipos_doc/success.xml +16 -0
- data/spec/fixtures/fe_param_get_tipos_iva/success.xml +16 -0
- data/spec/fixtures/fe_param_get_tipos_monedas/success.xml +22 -0
- data/spec/fixtures/fe_param_get_tipos_tributos/success.xml +16 -0
- data/spec/fixtures/fecae_solicitar/autorizacion_1_cbte.xml +30 -0
- data/spec/fixtures/fecae_solicitar/autorizacion_2_cbtes.xml +41 -0
- data/spec/fixtures/fecae_solicitar/observaciones.xml +40 -0
- data/spec/fixtures/login_cms/fault.xml +12 -0
- data/spec/fixtures/login_cms/success.xml +16 -0
- data/spec/fixtures/login_cms/token_expirado.xml +14 -0
- data/spec/fixtures/wsaa.wsdl +103 -0
- data/spec/fixtures/wsfe.wsdl +1372 -0
- data/spec/manual/autorizar_comprobante.rb +22 -0
- data/spec/manual/generar_keys.txt +8 -0
- data/spec/manual/obtener_ta.rb +18 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/matchers.rb +37 -0
- 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,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>
|