afipws 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/afipws/wsfe.rb CHANGED
@@ -1,68 +1,69 @@
1
1
  module Afipws
2
- class WSFE
3
- extend Forwardable
2
+ class WSFE < WSBase
4
3
  include TypeConversions
5
- attr_reader :wsaa, :client, :env
6
- def_delegators :wsaa, :ta, :auth, :cuit
7
4
 
8
5
  WSDL = {
9
- development: "https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL",
10
- # production: "https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL",
11
- production: Root + "/lib/afipws/wsfev1.wsdl",
12
- test: Root + "/spec/fixtures/wsfe.wsdl"
13
- }
6
+ development: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL',
7
+ # production: 'https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL',
8
+ production: Root + '/lib/afipws/wsdl/wsfev1.wsdl',
9
+ test: Root + '/spec/fixtures/wsfe.wsdl'
10
+ }.freeze
14
11
 
15
12
  def initialize options = {}
16
- @env = (options[:env] || :test).to_sym
17
- @wsaa = options[:wsaa] || WSAA.new(options.merge(service: 'wsfe'))
18
- @client = Client.new Hash(options[:savon]).reverse_merge(wsdl: WSDL[@env], ssl_version: :TLSv1, convert_request_keys_to: :camelcase)
13
+ super
14
+ @wsaa = WSAA.new options.merge(service: 'wsfe')
15
+ @client = Client.new Hash(options[:savon]).reverse_merge(wsdl: WSDL[env], convert_request_keys_to: :camelcase)
19
16
  end
20
17
 
21
18
  def dummy
22
- @client.fe_dummy
19
+ request :fe_dummy
23
20
  end
24
21
 
25
22
  def tipos_comprobantes
26
- r = @client.fe_param_get_tipos_cbte auth
23
+ r = request :fe_param_get_tipos_cbte, auth
27
24
  x2r get_array(r, :cbte_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
28
25
  end
29
26
 
30
27
  def tipos_documentos
31
- r = @client.fe_param_get_tipos_doc auth
28
+ r = request :fe_param_get_tipos_doc, auth
32
29
  x2r get_array(r, :doc_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
33
30
  end
34
31
 
35
32
  def tipos_monedas
36
- r = @client.fe_param_get_tipos_monedas auth
33
+ r = request :fe_param_get_tipos_monedas, auth
37
34
  x2r get_array(r, :moneda), fch_desde: :date, fch_hasta: :date
38
35
  end
39
36
 
40
37
  def tipos_iva
41
- r = @client.fe_param_get_tipos_iva auth
38
+ r = request :fe_param_get_tipos_iva, auth
42
39
  x2r get_array(r, :iva_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
43
40
  end
44
41
 
45
42
  def tipos_tributos
46
- r = @client.fe_param_get_tipos_tributos auth
43
+ r = request :fe_param_get_tipos_tributos, auth
47
44
  x2r get_array(r, :tributo_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
48
45
  end
49
46
 
50
47
  def puntos_venta
51
- r = @client.fe_param_get_ptos_venta auth
48
+ r = request :fe_param_get_ptos_venta, auth
52
49
  x2r get_array(r, :pto_venta), nro: :integer, fch_baja: :date, bloqueado: :boolean
53
50
  end
54
51
 
55
52
  def cotizacion moneda_id
56
- @client.fe_param_get_cotizacion(auth.merge(mon_id: moneda_id))[:result_get][:mon_cotiz].to_f
53
+ request(:fe_param_get_cotizacion, auth.merge(mon_id: moneda_id))[:result_get][:mon_cotiz].to_f
57
54
  end
58
55
 
59
56
  def autorizar_comprobantes opciones
60
57
  comprobantes = opciones[:comprobantes]
61
- request = { 'FeCAEReq' => {
62
- 'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
63
- 'FeDetReq' => { 'FECAEDetRequest' => comprobantes.map { |comprobante| comprobante_to_request comprobante }
64
- }}}
65
- r = @client.fecae_solicitar auth.merge r2x(request, cbte_fch: :date)
58
+ mensaje = {
59
+ 'FeCAEReq' => {
60
+ 'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
61
+ 'FeDetReq' => {
62
+ 'FECAEDetRequest' => comprobantes.map { |comprobante| comprobante_to_request comprobante }
63
+ }
64
+ }
65
+ }
66
+ r = request :fecae_solicitar, auth.merge(r2x(mensaje, cbte_fch: :date))
66
67
  r = Array.wrap(r[:fe_det_resp][:fecae_det_response]).map do |h|
67
68
  obs = Array.wrap(h[:observaciones] ? h[:observaciones][:obs] : nil)
68
69
  h.select_keys(:cae, :cae_fch_vto, :resultado).merge(cbte_nro: h[:cbte_desde], observaciones: obs)
@@ -78,7 +79,7 @@ module Afipws
78
79
  end
79
80
 
80
81
  def solicitar_caea
81
- convertir_rta_caea @client.fecaea_solicitar auth.merge(periodo_para_solicitud_caea)
82
+ convertir_rta_caea request(:fecaea_solicitar, auth.merge(periodo_para_solicitud_caea))
82
83
  rescue Afipws::WSError => e
83
84
  if e.errors.any? { |e| e[:code] == '15008' }
84
85
  consultar_caea fecha_inicio_quincena_siguiente
@@ -88,18 +89,22 @@ module Afipws
88
89
  end
89
90
 
90
91
  def consultar_caea fecha
91
- convertir_rta_caea @client.fecaea_consultar auth.merge(periodo_para_consulta_caea(fecha))
92
+ convertir_rta_caea request(:fecaea_consultar, auth.merge(periodo_para_consulta_caea(fecha)))
92
93
  end
93
94
 
94
95
  def informar_comprobantes_caea opciones
95
96
  comprobantes = opciones[:comprobantes]
96
- request = { 'FeCAEARegInfReq' => {
97
- 'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
98
- 'FeDetReq' => { 'FECAEADetRequest' => comprobantes.map do |comprobante|
99
- comprobante_to_request comprobante.merge('CAEA' => comprobante.delete(:caea))
100
- end
101
- }}}
102
- r = @client.fecaea_reg_informativo auth.merge r2x(request, cbte_fch: :date)
97
+ mensaje = {
98
+ 'FeCAEARegInfReq' => {
99
+ 'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
100
+ 'FeDetReq' => {
101
+ 'FECAEADetRequest' => comprobantes.map do |comprobante|
102
+ comprobante_to_request comprobante.merge('CAEA' => comprobante.delete(:caea))
103
+ end
104
+ }
105
+ }
106
+ }
107
+ r = request :fecaea_reg_informativo, auth.merge(r2x(mensaje, cbte_fch: :date))
103
108
  r = Array.wrap(r[:fe_det_resp][:fecaea_det_response]).map do |h|
104
109
  obs = Array.wrap(h[:observaciones] ? h[:observaciones][:obs] : nil)
105
110
  h.select_keys(:caea, :resultado).merge(cbte_nro: h[:cbte_desde], observaciones: obs)
@@ -108,19 +113,19 @@ module Afipws
108
113
  end
109
114
 
110
115
  def informar_caea_sin_movimientos caea, pto_vta
111
- @client.fecaea_sin_movimiento_informar(auth.merge('CAEA' => caea, 'PtoVta' => pto_vta))
116
+ request :fecaea_sin_movimiento_informar, auth.merge('CAEA' => caea, 'PtoVta' => pto_vta)
112
117
  end
113
118
 
114
119
  def ultimo_comprobante_autorizado opciones
115
- @client.fe_comp_ultimo_autorizado(auth.merge(opciones))[:cbte_nro].to_i
120
+ request(:fe_comp_ultimo_autorizado, auth.merge(opciones))[:cbte_nro].to_i
116
121
  end
117
122
 
118
123
  def consultar_comprobante opciones
119
- @client.fe_comp_consultar(auth.merge(fe_comp_cons_req: opciones))[:result_get]
124
+ request(:fe_comp_consultar, auth.merge(fe_comp_cons_req: opciones))[:result_get]
120
125
  end
121
126
 
122
127
  def cant_max_registros_x_lote
123
- @client.fe_comp_tot_x_request(auth)[:reg_x_req].to_i
128
+ request(:fe_comp_tot_x_request, auth)[:reg_x_req].to_i
124
129
  end
125
130
 
126
131
  def periodo_para_solicitud_caea
@@ -137,7 +142,21 @@ module Afipws
137
142
  hoy.day <= 15 ? hoy.change(day: 16) : hoy.next_month.change(day: 1)
138
143
  end
139
144
 
145
+ def auth
146
+ {auth: wsaa.auth.merge(cuit: cuit)}
147
+ end
148
+
140
149
  private
150
+
151
+ def request action, body = nil
152
+ response = @client.request(action, body).to_hash[:"#{action}_response"][:"#{action}_result"]
153
+ if response[:errors]
154
+ raise WSError, Array.wrap(response[:errors][:err])
155
+ else
156
+ response
157
+ end
158
+ end
159
+
141
160
  def get_array response, array_element
142
161
  Array.wrap response[:result_get][array_element]
143
162
  end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Hash do
4
- context "select_keys" do
5
- it "debería tomar los values de las keys indicadas" do
4
+ context 'select_keys' do
5
+ it 'debería tomar los values de las keys indicadas' do
6
6
  hash = Hash[1, 2, 3, 4]
7
7
  hash.select_keys(1).should == {1 => 2}
8
8
  hash.select_keys(1, 3).should == {1 => 2, 3 => 4}
@@ -10,11 +10,11 @@ describe Hash do
10
10
  hash.select_keys(5, 3).should == {3 => 4}
11
11
  end
12
12
  end
13
-
14
- context "has_entries?" do
13
+
14
+ context 'has_entries?' do
15
15
  subject { Hash[1, 2, 3, 4] }
16
-
17
- it "debería devolver true cuando self incluye todas las entries del hash parametro" do
16
+
17
+ it 'debería devolver true cuando self incluye todas las entries del hash parametro' do
18
18
  should have_entries 1 => 2
19
19
  should have_entries 3 => 4, 1 => 2
20
20
  should_not have_entries 1 => 3
@@ -1,29 +1,28 @@
1
- # coding: utf-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe Afipws::TypeConversions do
5
4
  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}
5
+
6
+ context 'r2x' do
7
+ it 'debería convertir values de hashes a xml types' do
8
+ r2x({fecha: Date.new(2011, 1, 2), id: 1}, fecha: :date).should == {fecha: '20110102', id: 1}
10
9
  r2x({container: {fecha: Date.new(2011, 1, 2)}}, fecha: :date).should == {container: {fecha: '20110102'}}
11
10
  end
12
11
 
13
- it "debería convertir values de hashes aunque estén en arrays" do
12
+ it 'debería convertir values de hashes aunque estén en arrays' do
14
13
  r2x([{fecha: Date.new(2011, 1, 2)}], fecha: :date).should == [{fecha: '20110102'}]
15
14
  r2x({container: [{fecha: Date.new(2011, 1, 2)}, {fecha: Date.new(2011, 1, 3)}]}, fecha: :date).should == {container: [{fecha: '20110102'}, {fecha: '20110103'}]}
16
15
  end
17
16
  end
18
-
19
- context "x2r" do
20
- it "deberia convertir values de hashes de xml types a ruby" do
17
+
18
+ context 'x2r' do
19
+ it 'deberia convertir values de hashes de xml types a ruby' do
21
20
  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'}
21
+ .should == {fecha: Date.new(2011, 1, 2), id: 1, total: 1.23, obs: 'algo'}
23
22
  x2r({container: {id: '1'}}, id: :integer).should == {container: {id: 1}}
24
23
  end
25
-
26
- it "debería hacer la conversión en arrays también" do
24
+
25
+ it 'debería hacer la conversión en arrays también' do
27
26
  x2r({container: [{id: '1'}, {id: '2'}]}, id: :integer).should == {container: [{id: 1}, {id: 2}]}
28
27
  end
29
28
  end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ module Afipws
4
+ describe WSConstanciaInscripcion do
5
+ let(:ta) { {token: 't', sign: 's'} }
6
+ let(:ws) { WSConstanciaInscripcion.new(cuit: '1').tap { |ws| ws.wsaa.stubs auth: ta } }
7
+ let(:auth) { ta.merge(cuit_representada: '1') }
8
+
9
+ context 'métodos API' do
10
+ it 'dummy' do
11
+ savon.expects(:dummy).returns(fixture('constancia_inscripcion_dummy/success'))
12
+ ws.dummy.should == { appserver: 'OK', dbserver: 'OK', authserver: 'OK' }
13
+ end
14
+
15
+ it 'debería devolver un hash con los datos generales y regímenes impositivos' do
16
+ savon.expects(:get_persona)
17
+ .with(message: auth.merge(id_persona: '20294834487'))
18
+ .returns(fixture('constancia_inscripcion_get_persona/success'))
19
+ r = ws.get_persona '20294834487'
20
+ r[:datos_generales].should have_entries(
21
+ estado_clave: 'ACTIVO', mes_cierre: '6', razon_social: 'LA REGALERIA S A',
22
+ tipo_clave: 'CUIT', tipo_persona: 'JURIDICA'
23
+ )
24
+ r[:datos_generales][:domicilio_fiscal].should have_entries(
25
+ cod_postal: '2300', descripcion_provincia: 'SANTA FE',
26
+ direccion: 'AV SIEMPRE VIVA 123', localidad: 'NUEVA YORK', tipo_domicilio: 'FISCAL'
27
+ )
28
+ r[:datos_regimen_general][:actividad].should have_entries(
29
+ id_actividad: '477330', nomenclador: '883', orden: '2', periodo: '201311'
30
+ )
31
+ r[:datos_regimen_general][:impuesto][1].should have_entries(
32
+ descripcion_impuesto: 'IVA', id_impuesto: '30', periodo: '198903'
33
+ )
34
+ r[:datos_regimen_general][:regimen].should have_entries(
35
+ id_impuesto: '208', id_regimen: '159', periodo: '199403'
36
+ )
37
+ end
38
+
39
+ it 'cuando hay errores en la constancia sigue la misma lógica' do
40
+ savon.expects(:get_persona).with(message: auth).returns(fixture('constancia_inscripcion_get_persona/failure'))
41
+ r = ws.get_persona '20294834487'
42
+ r[:error_regimen_general].should have_entries(
43
+ error: 'El contribuyente cuenta con impuestos con baja de oficio por Decreto 1299/98',
44
+ mensaje: 'No cumple con las condiciones para enviar datos del regimen general'
45
+ )
46
+ end
47
+ end
48
+
49
+ context 'entorno' do
50
+ it 'debería usar las url para development cuando el env es development' do
51
+ Client.expects(:new).with(wsdl: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl')
52
+ Client.expects(:new).with(wsdl: 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL', soap_version: 1)
53
+ wsci = WSConstanciaInscripcion.new env: :development
54
+ wsci.env.should == :development
55
+ end
56
+
57
+ it 'debería usar las url para production cuando el env es production' do
58
+ Client.expects(:new).with(wsdl: 'https://wsaa.afip.gov.ar/ws/services/LoginCms?wsdl')
59
+ Client.expects(:new).with(wsdl: 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL', soap_version: 1)
60
+ wsci = WSConstanciaInscripcion.new env: 'production'
61
+ wsci.env.should == :production
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,75 +1,83 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Afipws::WSAA do
4
- context "generación documento tra" do
5
- it "debería generar xml" do
6
- Time.stubs(:now).returns Time.new(2001, 12, 31, 12, 0, 0, '-03:00')
7
- xml = subject.generar_tra 'wsfe', 2400
8
- xml.should match_xpath "/loginTicketRequest/header/uniqueId", Time.now.to_i.to_s
9
- xml.should match_xpath "/loginTicketRequest/header/generationTime", "2001-12-31T11:20:00-03:00"
10
- xml.should match_xpath "/loginTicketRequest/header/expirationTime", "2001-12-31T12:40:00-03:00"
11
- xml.should match_xpath "/loginTicketRequest/service", "wsfe"
3
+ module Afipws
4
+ describe WSAA do
5
+ context 'generación documento tra' do
6
+ it 'debería generar xml' do
7
+ Time.stubs(:now).returns Time.new(2001, 12, 31, 12, 0, 0, '-03: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
12
14
  end
13
- end
14
15
 
15
- context "firmado del tra" do
16
- it "debería firmar el tra usando el certificado y la clave privada" do
17
- key = File.read(File.dirname(__FILE__) + '/test.key')
18
- crt = File.read(File.dirname(__FILE__) + '/test.crt')
19
- tra = subject.generar_tra 'wsfe', 2400
20
- subject.firmar_tra(tra, key, crt).to_s.should =~ /BEGIN PKCS7/
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
21
23
  end
22
- end
23
24
 
24
- context "codificación del tra" do
25
- it "debería quitarle el header y footer" do
26
- subject.codificar_tra(OpenSSL::PKCS7.new).should_not include 'BEGIN', 'END'
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_not include 'BEGIN', 'END'
28
+ end
27
29
  end
28
- end
29
30
 
30
- context "login" do
31
- it "debería mandar el TRA al WS y obtener el TA" do
32
- ws = Afipws::WSAA.new key: 'key', cert: 'cert'
33
- ws.expects(:tra).with('key', 'cert', 'wsfe', 2400).returns('tra')
34
- savon.expects(:login_cms).with(message: {in0: 'tra'}).returns(fixture('login_cms/success'))
35
- ta = ws.login
36
- ta[:token].should == 'PD94='
37
- ta[:sign].should == 'i9xDN='
38
- ta[:generation_time].should == Time.new(2011, 1, 12, 18, 57, 4, '-03:00')
39
- ta[:expiration_time].should == Time.new(2011, 1, 13, 6, 57, 4, '-03:00')
40
- end
31
+ context 'login' do
32
+ it 'debería mandar el TRA al WS y obtener el TA' do
33
+ ws = WSAA.new key: 'key', cert: 'cert'
34
+ ws.expects(:tra).with('key', 'cert', 'wsfe', 2400).returns('tra')
35
+ savon.expects(:login_cms).with(message: {in0: 'tra'}).returns(fixture('login_cms/success'))
36
+ ta = ws.login
37
+ ta[:token].should == 'PD94='
38
+ ta[:sign].should == 'i9xDN='
39
+ ta[:generation_time].should == Time.new(2011, 1, 12, 18, 57, 4, '-03:00')
40
+ ta[:expiration_time].should == Time.new(2011, 1, 13, 6, 57, 4, '-03:00')
41
+ end
41
42
 
42
- it "debería encapsular SOAP Faults" do
43
- subject.stubs(:tra).returns('')
44
- savon.expects(:login_cms).with(message: :any).returns(fixture('login_cms/fault'))
45
- lambda { subject.login }.should raise_error Afipws::WSError, /CMS no es valido/
43
+ it 'debería encapsular SOAP Faults' do
44
+ subject.stubs(:tra).returns('')
45
+ savon.expects(:login_cms).with(message: :any).returns(fixture('login_cms/fault'))
46
+ -> { subject.login }.should raise_error WSError, /CMS no es valido/
47
+ end
46
48
  end
47
- end
48
49
 
49
- context "auth" do
50
- before do
51
- FileUtils.rm_rf Dir.glob('tmp/*ta.dump')
52
- Time.stubs(:now).returns(Time.local(2010, 1, 1))
53
- end
50
+ context 'auth' do
51
+ before do
52
+ FileUtils.rm_rf Dir.glob('tmp/*ta.dump')
53
+ Time.stubs(:now).returns(Time.local(2010, 1, 1))
54
+ end
54
55
 
55
- it "debería cachear TA en la instancia y disco" do
56
- ws = Afipws::WSAA.new
57
- ws.expects(:login).once.returns(ta = {token: 'token', sign: 'sign', expiration_time: Time.now + 60})
58
- ws.auth
59
- ws.auth
60
- ws.ta.should equal ta
56
+ it 'debería devolver hash con token y sign' do
57
+ ws = WSAA.new
58
+ ws.expects(:login).once.returns(token: 'token', sign: 'sign', expiration_time: Time.now + 60)
59
+ ws.auth.should == {token: 'token', sign: 'sign'}
60
+ end
61
61
 
62
- ws = Afipws::WSAA.new
63
- ws.auth
64
- ws.ta.should == ta
65
- end
62
+ it 'debería cachear TA en la instancia y disco' do
63
+ ws = WSAA.new
64
+ ws.expects(:login).once.returns(ta = {token: 'token', sign: 'sign', expiration_time: Time.now + 60})
65
+ ws.auth
66
+ ws.auth
67
+ ws.ta.should equal ta
68
+
69
+ ws = WSAA.new
70
+ ws.auth
71
+ ws.ta.should == ta
72
+ end
66
73
 
67
- it "si el TA expiró debería ejecutar solicitar uno nuevo" do
68
- subject.expects(:login).twice.returns(token: 't1', expiration_time: Time.now - 2).then.returns(token: 't2')
69
- subject.auth
70
- subject.ta[:token].should == 't1'
71
- subject.auth
72
- subject.ta[:token].should == 't2'
74
+ it 'si el TA expiró debería ejecutar solicitar uno nuevo' do
75
+ subject.expects(:login).twice.returns(token: 't1', expiration_time: Time.now - 2).then.returns(token: 't2')
76
+ subject.auth
77
+ subject.ta[:token].should == 't1'
78
+ subject.auth
79
+ subject.ta[:token].should == 't2'
80
+ end
73
81
  end
74
82
  end
75
83
  end