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