arca.rb 1.0.0

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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +8 -0
  3. data/.devcontainer/devcontainer.json +12 -0
  4. data/.github/dependabot.yml +12 -0
  5. data/.github/workflows/ci.yml +16 -0
  6. data/.github/workflows/release.yml +37 -0
  7. data/.gitignore +8 -0
  8. data/.mise.toml +2 -0
  9. data/.rubocop.yml +8 -0
  10. data/.ruby-version +1 -0
  11. data/CHANGELOG.md +19 -0
  12. data/CONTRIBUTING.md +48 -0
  13. data/Gemfile +4 -0
  14. data/LICENSE +22 -0
  15. data/README.md +209 -0
  16. data/Rakefile +10 -0
  17. data/SECURITY.md +14 -0
  18. data/arca.gemspec +40 -0
  19. data/bin/console +7 -0
  20. data/lib/arca/client.rb +29 -0
  21. data/lib/arca/core_ext/hash.rb +13 -0
  22. data/lib/arca/errors/error.rb +13 -0
  23. data/lib/arca/errors/network_error.rb +15 -0
  24. data/lib/arca/errors/response_error.rb +18 -0
  25. data/lib/arca/errors/server_error.rb +6 -0
  26. data/lib/arca/persona_service_a100.rb +51 -0
  27. data/lib/arca/persona_service_a4.rb +34 -0
  28. data/lib/arca/persona_service_a5.rb +46 -0
  29. data/lib/arca/type_conversions.rb +44 -0
  30. data/lib/arca/version.rb +5 -0
  31. data/lib/arca/w_cons_declaracion.rb +66 -0
  32. data/lib/arca/ws_constancia_inscripcion.rb +34 -0
  33. data/lib/arca/wsaa.rb +140 -0
  34. data/lib/arca/wscdc.rb +149 -0
  35. data/lib/arca/wsfe.rb +205 -0
  36. data/lib/arca/wsfecred.rb +438 -0
  37. data/lib/arca/wsrgiva.rb +72 -0
  38. data/lib/arca.rb +31 -0
  39. data/test/arca/client_test.rb +43 -0
  40. data/test/arca/core_ext/hash_test.rb +15 -0
  41. data/test/arca/persona_service_a100_test.rb +45 -0
  42. data/test/arca/persona_service_a4_test.rb +31 -0
  43. data/test/arca/persona_service_a5_test.rb +31 -0
  44. data/test/arca/test.crt +19 -0
  45. data/test/arca/test.key +28 -0
  46. data/test/arca/type_conversions_test.rb +43 -0
  47. data/test/arca/w_cons_declaracion_test.rb +86 -0
  48. data/test/arca/ws_constancia_inscripcion_test.rb +87 -0
  49. data/test/arca/wsaa_test.rb +80 -0
  50. data/test/arca/wscdc_test.rb +103 -0
  51. data/test/arca/wsfe_test.rb +319 -0
  52. data/test/arca/wsfecred_test.rb +162 -0
  53. data/test/arca/wsrgiva_test.rb +91 -0
  54. data/test/fixtures/wconsdeclaracion/detallada_estado/success.xml +24 -0
  55. data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_fecha_success.xml +39 -0
  56. data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_id_inexistente.xml +16 -0
  57. data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_id_success.xml +29 -0
  58. data/test/fixtures/wconsdeclaracion/dummy/success.xml +12 -0
  59. data/test/fixtures/wconsdeclaracion/wconsdeclaracion.wsdl +2976 -0
  60. data/test/fixtures/ws_sr_constancia_inscripcion/dummy/success.xml +11 -0
  61. data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/failure.xml +35 -0
  62. data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/fault.xml +8 -0
  63. data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/success.xml +53 -0
  64. data/test/fixtures/ws_sr_constancia_inscripcion/ws_constancia_inscripcion.wsdl +230 -0
  65. data/test/fixtures/ws_sr_padron_a100/company_types/success.xml +23 -0
  66. data/test/fixtures/ws_sr_padron_a100/dummy/success.xml +11 -0
  67. data/test/fixtures/ws_sr_padron_a100/jurisdictions/success.xml +31 -0
  68. data/test/fixtures/ws_sr_padron_a100/public_organisms/success.xml +23 -0
  69. data/test/fixtures/ws_sr_padron_a100.wsdl +125 -0
  70. data/test/fixtures/ws_sr_padron_a4/dummy/success.xml +11 -0
  71. data/test/fixtures/ws_sr_padron_a4/get_persona/success.xml +133 -0
  72. data/test/fixtures/ws_sr_padron_a4.wsdl +229 -0
  73. data/test/fixtures/ws_sr_padron_a5/dummy/success.xml +11 -0
  74. data/test/fixtures/ws_sr_padron_a5/get_persona/success.xml +62 -0
  75. data/test/fixtures/ws_sr_padron_a5.wsdl +283 -0
  76. data/test/fixtures/wsaa/login_cms/fault.xml +12 -0
  77. data/test/fixtures/wsaa/login_cms/success.xml +16 -0
  78. data/test/fixtures/wsaa/login_cms/token_expirado.xml +14 -0
  79. data/test/fixtures/wsaa/wsaa.wsdl +103 -0
  80. data/test/fixtures/wscdc/comprobante_constatar/success.xml +22 -0
  81. data/test/fixtures/wscdc/comprobante_constatar/with_errors.xml +28 -0
  82. data/test/fixtures/wscdc/comprobante_dummy/success.xml +11 -0
  83. data/test/fixtures/wscdc/comprobantes_modalidad_consultar/success.xml +22 -0
  84. data/test/fixtures/wscdc/comprobantes_tipo_consultar/success.xml +22 -0
  85. data/test/fixtures/wscdc/documentos_tipo_consultar/success.xml +16 -0
  86. data/test/fixtures/wscdc/opcionales_tipo_consultar/success.xml +14 -0
  87. data/test/fixtures/wscdc/wscdc.wsdl +305 -0
  88. data/test/fixtures/wsfe/fe_comp_consultar/success.xml +41 -0
  89. data/test/fixtures/wsfe/fe_comp_tot_x_request/success.xml +9 -0
  90. data/test/fixtures/wsfe/fe_comp_ultimo_autorizado/success.xml +11 -0
  91. data/test/fixtures/wsfe/fe_dummy/success.xml +11 -0
  92. data/test/fixtures/wsfe/fe_param_get_cotizacion/dolar.xml +13 -0
  93. data/test/fixtures/wsfe/fe_param_get_cotizacion/inexistente.xml +14 -0
  94. data/test/fixtures/wsfe/fe_param_get_ptos_venta/success.xml +22 -0
  95. data/test/fixtures/wsfe/fe_param_get_tipos_cbte/failure_1_error.xml +14 -0
  96. data/test/fixtures/wsfe/fe_param_get_tipos_cbte/failure_2_errors.xml +18 -0
  97. data/test/fixtures/wsfe/fe_param_get_tipos_cbte/success.xml +22 -0
  98. data/test/fixtures/wsfe/fe_param_get_tipos_concepto/success.xml +17 -0
  99. data/test/fixtures/wsfe/fe_param_get_tipos_doc/success.xml +16 -0
  100. data/test/fixtures/wsfe/fe_param_get_tipos_iva/success.xml +16 -0
  101. data/test/fixtures/wsfe/fe_param_get_tipos_monedas/success.xml +22 -0
  102. data/test/fixtures/wsfe/fe_param_get_tipos_opcional/success.xml +16 -0
  103. data/test/fixtures/wsfe/fe_param_get_tipos_tributos/success.xml +16 -0
  104. data/test/fixtures/wsfe/fecae_solicitar/autorizacion_1_cbte.xml +30 -0
  105. data/test/fixtures/wsfe/fecae_solicitar/autorizacion_2_cbtes.xml +41 -0
  106. data/test/fixtures/wsfe/fecae_solicitar/dos_observaciones.xml +40 -0
  107. data/test/fixtures/wsfe/fecae_solicitar/una_observacion.xml +36 -0
  108. data/test/fixtures/wsfe/fecaea_consultar/success.xml +17 -0
  109. data/test/fixtures/wsfe/fecaea_reg_informativo/informe_rtdo_parcial.xml +45 -0
  110. data/test/fixtures/wsfe/fecaea_sin_movimiento_informar/success.xml +12 -0
  111. data/test/fixtures/wsfe/fecaea_solicitar/caea_ya_otorgado.xml +18 -0
  112. data/test/fixtures/wsfe/fecaea_solicitar/error_distinto.xml +18 -0
  113. data/test/fixtures/wsfe/fecaea_solicitar/success.xml +17 -0
  114. data/test/fixtures/wsfe/wsfe.wsdl +1372 -0
  115. data/test/fixtures/wsfecred/aceptar_f_e_cred/success.xml +14 -0
  116. data/test/fixtures/wsfecred/consultar_comprobantes/success.xml +17 -0
  117. data/test/fixtures/wsfecred/consultar_cta_cte/success.xml +13 -0
  118. data/test/fixtures/wsfecred/consultar_ctas_ctes/success.xml +16 -0
  119. data/test/fixtures/wsfecred/consultar_tipos_formas_cancelacion/success.xml +14 -0
  120. data/test/fixtures/wsfecred/consultar_tipos_motivos_rechazo/success.xml +14 -0
  121. data/test/fixtures/wsfecred/consultar_tipos_retenciones/failure.xml +14 -0
  122. data/test/fixtures/wsfecred/consultar_tipos_retenciones/success.xml +14 -0
  123. data/test/fixtures/wsfecred/dummy/success.xml +11 -0
  124. data/test/fixtures/wsfecred/wsfecred.wsdl +147 -0
  125. data/test/fixtures/wsrgiva/consultar_constancia_por_lote/one_error.xml +14 -0
  126. data/test/fixtures/wsrgiva/consultar_constancia_por_lote/success.xml +26 -0
  127. data/test/fixtures/wsrgiva/dummy/success.xml +11 -0
  128. data/test/fixtures/wsrgiva/wsrgiva.wsdl +118 -0
  129. data/test/support/savon_extensions.rb +43 -0
  130. data/test/test_helper.rb +44 -0
  131. metadata +319 -0
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # WSRGIVA: Web Service del Régimen de Percepción de I.V.A. (ARCA).
4
+ # Consulta de situación fiscal por lote (hasta 100 contribuyentes).
5
+ # Documentación: Régimen de Percepción de I.V.A. v1.0 (03-04-2023).
6
+ module Arca
7
+ class WSRGIVA
8
+ WSDL = {
9
+ development: "https://fwshomo.afip.gov.ar/wsrgiva/services/RegimenPercepcionIVAService?wsdl",
10
+ production: "https://serviciosjava.afip.gov.ar/wsrgiva/services/RegimenPercepcionIVAService?wdsl",
11
+ test: "#{Root}/test/fixtures/wsrgiva/wsrgiva.wsdl"
12
+ }.freeze
13
+
14
+ attr_reader :wsaa, :cuit
15
+
16
+ def initialize(options = {})
17
+ @cuit = normalize_cuit(options[:cuit])
18
+ @wsaa = WSAA.new options.merge(service: "wsrgiva")
19
+ @client = Client.new Hash(options[:savon]).reverse_merge(
20
+ wsdl: WSDL[@wsaa.env],
21
+ soap_version: 1
22
+ )
23
+ end
24
+
25
+ def dummy
26
+ r = request(:dummy)[:return]
27
+ {
28
+ app_server: r[:appserver] || r[:app_server],
29
+ auth_server: r[:authserver] || r[:auth_server],
30
+ db_server: r[:dbserver] || r[:db_server]
31
+ }
32
+ end
33
+
34
+ # Consulta la situación fiscal de hasta 100 contribuyentes.
35
+ # cuits: array of 11-digit CUIT strings/integers (max 100).
36
+ # tipo_bienes_involucrados: 1 (único valor admitido; nuevo/usado).
37
+ # Returns array of constancia hashes (one per CUIT): success with
38
+ # fecha_consulta, id_contribuyente, descripcion_contribuyente, vigencia,
39
+ # codigo_leyenda, descripcion_leyenda, codigo_seguridad; or error with
40
+ # codigo_error, descripcion_error.
41
+ def consultar_constancia_por_lote(cuits, tipo_bienes_involucrados: 1)
42
+ cuits = Array(cuits).map { |c| c.to_s.gsub(/\D/, "") }
43
+ raise ArgumentError, "Maximum 100 CUITs per request" if cuits.size > 100
44
+ raise ArgumentError, "tipo_bienes_involucrados must be 1" if tipo_bienes_involucrados != 1
45
+
46
+ datos_transaccion = cuits.map do |cuit|
47
+ { cuit_contribuyente: cuit.to_i, tipo_bienes_involucrados: 1 }
48
+ end
49
+ message = {
50
+ auth_request: @wsaa.auth.merge(cuit_representada: cuit),
51
+ datos_transaccion_array: { datos_transaccion: datos_transaccion }
52
+ }
53
+ result = request(:consultar_constancia_por_lote_v2, message)[:return]
54
+ constancias = result[:constancia]
55
+ Array.wrap(constancias)
56
+ end
57
+
58
+ private
59
+
60
+ def request(action, body = nil)
61
+ @client.request(action, body).to_hash[:"#{action}_response"]
62
+ end
63
+
64
+ def normalize_cuit(value)
65
+ if value.nil? || value == ""
66
+ 0
67
+ else
68
+ value.to_s.gsub(/\D/, "").to_i
69
+ end
70
+ end
71
+ end
72
+ end
data/lib/arca.rb ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arca
4
+ Root = File.expand_path("..", __dir__)
5
+ end
6
+
7
+ require "forwardable"
8
+ require "builder"
9
+ require "base64"
10
+ require "httpclient"
11
+ require "savon"
12
+ require "nokogiri"
13
+ require "active_support"
14
+ require "active_support/core_ext"
15
+ require "arca/core_ext/hash"
16
+ require "arca/errors/error"
17
+ require "arca/errors/response_error"
18
+ require "arca/errors/server_error"
19
+ require "arca/errors/network_error"
20
+ require "arca/type_conversions"
21
+ require "arca/client"
22
+ require "arca/wsaa"
23
+ require "arca/wsfe"
24
+ require "arca/ws_constancia_inscripcion"
25
+ require "arca/persona_service_a4"
26
+ require "arca/persona_service_a5"
27
+ require "arca/persona_service_a100"
28
+ require "arca/w_cons_declaracion"
29
+ require "arca/wsrgiva"
30
+ require "arca/wscdc"
31
+ require "arca/wsfecred"
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class ClientTest < TestCase
7
+ def subject
8
+ @subject ||= Client.new(wsdl: Arca::WSFE::WSDL[:test])
9
+ end
10
+
11
+ def test_savon_soap_fault_se_encapsulan_en_server_error
12
+ savon.expects(:fe_dummy).returns(fixture("wsaa/login_cms/fault"))
13
+ error = assert_raises(ServerError) { subject.request :fe_dummy }
14
+ assert_match(/CMS no es valido/, error.message)
15
+ end
16
+
17
+ def test_savon_http_error_se_encapsulan_en_server_error
18
+ expect_savon_to_raise Savon::HTTPError, stub(code: 503, body: "Service Unavailable")
19
+ error = assert_raises(ServerError) { subject.request :fe_dummy }
20
+ assert_match(/Service Unavailable/, error.message)
21
+ end
22
+
23
+ def test_httpclient_timeout_error_se_encapsulan_en_network_error_y_no_es_retriable
24
+ expect_savon_to_raise HTTPClient::ReceiveTimeoutError, "execution expired"
25
+ error = assert_raises(NetworkError) { subject.request :fe_dummy }
26
+ assert_match(/execution expired/, error.message)
27
+ assert_equal false, error.retriable?
28
+ end
29
+
30
+ def test_httpclient_connect_timeout_error_se_encapsulan_en_network_error_y_es_retriable
31
+ expect_savon_to_raise HTTPClient::ConnectTimeoutError, "execution expired"
32
+ error = assert_raises(NetworkError) { subject.request :fe_dummy }
33
+ assert_match(/execution expired/, error.message)
34
+ assert_equal true, error.retriable?
35
+ end
36
+
37
+ private
38
+
39
+ def expect_savon_to_raise(error_class, message)
40
+ subject.instance_eval("@savon", __FILE__, __LINE__).expects(:call).raises(error_class, message)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class HashCoreExtTest < Minitest::Test
6
+ using Arca::CoreExt::Hash
7
+
8
+ def test_select_keys_toma_los_values_de_las_keys_indicadas
9
+ hash = { 1 => 2, 3 => 4 }
10
+ assert_equal({ 1 => 2 }, hash.select_keys(1))
11
+ assert_equal({ 1 => 2, 3 => 4 }, hash.select_keys(1, 3))
12
+ assert_equal({}, hash.select_keys(5))
13
+ assert_equal({ 3 => 4 }, hash.select_keys(5, 3))
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class PersonaServiceA100Test < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= PersonaServiceA100.new(cuit: "12345678912").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def auth_message
16
+ ta.merge(cuitRepresentada: "12345678912")
17
+ end
18
+
19
+ def test_dummy
20
+ savon.expects(:dummy).returns(fixture("ws_sr_padron_a100/dummy/success"))
21
+ assert_equal({ appserver: "OK", authserver: "OK", dbserver: "OK" }, ws.dummy)
22
+ end
23
+
24
+ def test_jurisdictions
25
+ savon.expects(:get_parameter_collection_by_name)
26
+ .with(message: auth_message.merge(collectionName: "SUPA.E_PROVINCIA"))
27
+ .returns(fixture("ws_sr_padron_a100/jurisdictions/success"))
28
+ assert_hash_includes ws.jurisdictions, name: "SUPA.E_PROVINCIA"
29
+ end
30
+
31
+ def test_company_types
32
+ savon.expects(:get_parameter_collection_by_name)
33
+ .with(message: auth_message.merge(collectionName: "SUPA.TIPO_EMPRESA_JURIDICA"))
34
+ .returns(fixture("ws_sr_padron_a100/company_types/success"))
35
+ assert_hash_includes ws.company_types, name: "SUPA.TIPO_EMPRESA_JURIDICA"
36
+ end
37
+
38
+ def test_public_organisms
39
+ savon.expects(:get_parameter_collection_by_name)
40
+ .with(message: auth_message.merge(collectionName: "SUPA.E_ORGANISMO_INFORMANTE"))
41
+ .returns(fixture("ws_sr_padron_a100/public_organisms/success"))
42
+ assert_hash_includes ws.public_organisms, name: "SUPA.E_ORGANISMO_INFORMANTE"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class PersonaServiceA4Test < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= PersonaServiceA4.new(cuit: "12345678912").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def auth_message
16
+ ta.merge(cuitRepresentada: "12345678912")
17
+ end
18
+
19
+ def test_dummy
20
+ savon.expects(:dummy).returns(fixture("ws_sr_padron_a4/dummy/success"))
21
+ assert_equal({ appserver: "OK", authserver: "OK", dbserver: "OK" }, ws.dummy)
22
+ end
23
+
24
+ def test_get_persona
25
+ savon.expects(:get_persona)
26
+ .with(message: auth_message.merge(idPersona: "98765432198"))
27
+ .returns(fixture("ws_sr_padron_a4/get_persona/success"))
28
+ assert_hash_includes ws.get_persona("98765432198"), apellido: "ERNESTO DANIEL"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class PersonaServiceA5Test < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= PersonaServiceA5.new(cuit: "12345678912").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def auth_message
16
+ ta.merge(cuitRepresentada: "12345678912")
17
+ end
18
+
19
+ def test_dummy
20
+ savon.expects(:dummy).returns(fixture("ws_sr_padron_a5/dummy/success"))
21
+ assert_equal({ appserver: "OK", authserver: "OK", dbserver: "OK" }, ws.dummy)
22
+ end
23
+
24
+ def test_get_persona
25
+ savon.expects(:get_persona)
26
+ .with(message: auth_message.merge(idPersona: "98765432198"))
27
+ .returns(fixture("ws_sr_padron_a5/get_persona/success"))
28
+ assert ws.get_persona("98765432198").key?(:datos_generales)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDDzCCAfegAwIBAgIUdt0TOIYoh1GRdF20ue4cL9lnlmYwDQYJKoZIhvcNAQEL
3
+ BQAwFzEVMBMGA1UEAwwMYXJjYXNkay10ZXN0MB4XDTI2MDEzMTEzNTAwM1oXDTI3
4
+ MDEzMTEzNTAwM1owFzEVMBMGA1UEAwwMYXJjYXNkay10ZXN0MIIBIjANBgkqhkiG
5
+ 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuznTwETEgl17pfqJOVAAQFDPHCFlXZF0+hlA
6
+ b49Qs7wZA6nCE7JYadyT2m5sis3TnyEzilFQRKh/ogbXCmAFPVR7SyGPpUn2R+o7
7
+ jI4dkkIRi/awr02mC7YhZcTtYmRfr5SEOrqQGDy3Y8+u2NMw4wrLsY+M6vjG+XCd
8
+ z4z4szpJuI61R5IhlL0hEItTi0DnZluh86jgmDT5rZ/PF+HpnM1Gw3O415jmWR3n
9
+ wgrdlEZWPvC/GFZnImMKJZcIOEJRJNWa2dxqiQNnJggwdJE9eAaSDNS8S31fmchK
10
+ KRKOCfSRseW6m5TzwkA46Y2bgBmTiYeXs9+brKIYYrN54V6JUwIDAQABo1MwUTAd
11
+ BgNVHQ4EFgQUB1hDQYM66Xdd8Kuz4RZ2FOjn4acwHwYDVR0jBBgwFoAUB1hDQYM6
12
+ 6Xdd8Kuz4RZ2FOjn4acwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
13
+ AQEAKkOfdp74GQgynVacmzBfBZanYZZwmyJgozEFwNk90sE/4ul3uzy9kaDw9m6Z
14
+ dUB2ZfwQSkkGcKN/D67PVpAOtUCjow3qEyPkr8Lu6YJR275J1L0sNfeffUFPslZy
15
+ yOdRXHB08ixl8h1tj46R4JinL92JljlJz8v2U5YxPgJNbmgEpiKFYeI2lL+jAbqO
16
+ PJowIhkC2rruFmGOhheLziCI035AJRK+Xq0Kof0pLPEzpM/We2TSGftZxOm0Da9z
17
+ rGvlEWCuGDw1LehbIOPFXMx/xwkbg9hZiO80AjstqVX/yBWfG7r4KN4W/DxFYt1y
18
+ bgmc8mIlyTHDlLMy8ngCYDNC3Q==
19
+ -----END CERTIFICATE-----
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7OdPARMSCXXul
3
+ +ok5UABAUM8cIWVdkXT6GUBvj1CzvBkDqcITslhp3JPabmyKzdOfITOKUVBEqH+i
4
+ BtcKYAU9VHtLIY+lSfZH6juMjh2SQhGL9rCvTaYLtiFlxO1iZF+vlIQ6upAYPLdj
5
+ z67Y0zDjCsuxj4zq+Mb5cJ3PjPizOkm4jrVHkiGUvSEQi1OLQOdmW6HzqOCYNPmt
6
+ n88X4emczUbDc7jXmOZZHefCCt2URlY+8L8YVmciYwollwg4QlEk1ZrZ3GqJA2cm
7
+ CDB0kT14BpIM1LxLfV+ZyEopEo4J9JGx5bqblPPCQDjpjZuAGZOJh5ez35usohhi
8
+ s3nhXolTAgMBAAECggEAXI5RWq8EUIhDXMHWvcEJZsIsKPVvhYqngA4ktyHr3PbD
9
+ jPaKja8wmyDi7OyC9zmagQPqVVouasq70g88lpHydSfDDdjJCQbf3Bx1FN6aytej
10
+ kgRBw2AJEqgWqZdpXSdO0F+E4P2ix4CYjpy4jNMWy17mZOCY4v5aayzbryO7POpe
11
+ SGpr7+1uglqKMlrvFUrUEnxhvycYH3c7PWrFhhm2toQfYleyyWiJA8TsilR0jPhv
12
+ /GePDu6uF/g0Qs7Fc1EFDMPvxW+D7820BMwgSuELLUg2XbvFkPH7junRzvvuW++n
13
+ Vnlcl5GB9T1MszBVRdOplYtPFBVUPMtzm8n+ufUuSQKBgQDrbP2Y7UGaMYXMfSOQ
14
+ jJdEWFM0xqPUzmFVGHVmJjyHic+dXMgwvgkQrjIOrepEMlw7wC7tcNG4bUkTE9YL
15
+ HO6DJakybNQJ+jyerQrsXfCC75NlxZLPsjOG01gr+8SUCdJQCGu3Wi5mGkfhbgQV
16
+ yXLQXeQxseh75PpnAB8pQp4YewKBgQDLln8AXtbaROa4x+D6CBYEL8v8O+tgIjAB
17
+ zPZ1Fvah/guGn1f3nUJdL4O65oDnoPAOxTooHBvEzJMhYN1LTN/kqQbApvkPmW9F
18
+ NAz4ParAWpoLMNn36IBqSrYzCetZm2NoL21KZei+bUNbJiTzeCqDrfHE/2PgEoBg
19
+ FGRnSEP3CQKBgQDTGkI0NNsUdr+xY6zWWxrw7/p8YnpZwk3IzkvHMxYnu01tn9rq
20
+ yhy61liQjSZ5zGakNWpfA0ErDOPvtWPDR0ggVU7opmlkIPzmk+gtlvapkkYrhgRl
21
+ NTe6+BwiJHpa/IuXtFVSbg0ZBQvbepkzKBZJ/Uc3wH3lSqe2YIeQqem1rQKBgFj/
22
+ /6E/1JkyydI5vwZPBqDp7DjmUO2DxIzk91EUqtkCYDOH8ULUQrDOFr5cCjo4RvmO
23
+ CvCB6TnNXPyYheVnQ/GIWuVZmUPShawxJwJWoxDYCsOdpYwU3h6ZbrE9Qt+3aGuh
24
+ YBvIFUk6JtnwAPNWsu9B2ZGPPDA2plxaTdJA60VRAoGACXSbVz7cECvkmuSCg03s
25
+ a+FYZs/aeKifsOW5D/ikvmvUu2pMaWN1eL5s5atkUSkFJ0zdnCPjtkrccLcFKJFi
26
+ 7ZRRLu3bc+jYlq37nSYyUop7fpds0IT2ATYlEb956nrDbEipMuY2epGmVQGk/GUI
27
+ PcCN51NZ5hfoG1eda5xlZmw=
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class TypeConversionsTest < TestCase
7
+ include Arca::TypeConversions
8
+
9
+ def test_r2x_convierte_values_de_hashes_a_xml_types
10
+ assert_equal(
11
+ { fecha: "20110102", id: 1 },
12
+ r2x({ fecha: Date.new(2011, 1, 2), id: 1 }, fecha: :date)
13
+ )
14
+ assert_equal(
15
+ { container: { fecha: "20110102" } },
16
+ r2x({ container: { fecha: Date.new(2011, 1, 2) } }, fecha: :date)
17
+ )
18
+ end
19
+
20
+ def test_r2x_convierte_values_aunque_esten_en_arrays
21
+ assert_equal [ { fecha: "20110102" } ], r2x([ { fecha: Date.new(2011, 1, 2) } ], fecha: :date)
22
+ assert_equal(
23
+ { container: [ { fecha: "20110102" }, { fecha: "20110103" } ] },
24
+ r2x({ container: [ { fecha: Date.new(2011, 1, 2) }, { fecha: Date.new(2011, 1, 3) } ] }, fecha: :date)
25
+ )
26
+ end
27
+
28
+ def test_x2r_convierte_xml_types_a_ruby
29
+ assert_equal(
30
+ { fecha: Date.new(2011, 1, 2), id: 1, total: 1.23, obs: "algo" },
31
+ x2r({ fecha: "20110102", id: "1", total: "1.23", obs: "algo" }, fecha: :date, id: :integer, total: :float)
32
+ )
33
+ assert_equal({ container: { id: 1 } }, x2r({ container: { id: "1" } }, id: :integer))
34
+ end
35
+
36
+ def test_x2r_hace_la_conversion_en_arrays
37
+ assert_equal(
38
+ { container: [ { id: 1 }, { id: 2 } ] },
39
+ x2r({ container: [ { id: "1" }, { id: "2" } ] }, id: :integer)
40
+ )
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WConsDeclaracionTest < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= WConsDeclaracion.new(env: :test, cuit: "23076925089").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def test_utiliza_los_parametros_correctos_en_el_wsaa
16
+ assert_equal "wconsdeclaracion", ws.wsaa.service
17
+ assert_equal "23076925089", ws.wsaa.cuit
18
+ assert_equal :test, ws.wsaa.env
19
+ end
20
+
21
+ def test_dummy
22
+ savon.expects(:dummy).returns(fixture("wconsdeclaracion/dummy/success"))
23
+ assert_equal({ app_server: "OK", db_server: "OK", auth_server: "OK" }, ws.dummy)
24
+ end
25
+
26
+ def test_detallada_lista_declaraciones_por_id
27
+ message = with_auth_section(
28
+ "argDetalladasListaParams" => {
29
+ "CuitImportadorExportador" => "23076925089",
30
+ "IdentificadorDeclaracion" => "19093SIMI000434X"
31
+ }
32
+ )
33
+ savon.expects(:detallada_lista_declaraciones).with(message: message)
34
+ .returns(fixture("wconsdeclaracion/detallada_lista_declaraciones/por_id_success"))
35
+ declaracion = ws.detallada_lista_declaraciones identificador_declaracion: "19093SIMI000434X"
36
+ assert_hash_includes declaracion, identificador_declaracion: "19093SIMI000434X",
37
+ cuit_importador_exportador: "23076925089"
38
+ end
39
+
40
+ def test_detallada_lista_declaraciones_por_fecha
41
+ message = with_auth_section(
42
+ "argDetalladasListaParams" => {
43
+ "CuitImportadorExportador" => "23076925089",
44
+ "FechaOficializacionDesde" => "2019-04-01T00:00:00-03:00",
45
+ "FechaOficializacionHasta" => "2019-04-30T00:00:00-03:00"
46
+ }
47
+ )
48
+ savon.expects(:detallada_lista_declaraciones).with(message: message)
49
+ .returns(fixture("wconsdeclaracion/detallada_lista_declaraciones/por_fecha_success"))
50
+ declaraciones = ws.detallada_lista_declaraciones(
51
+ fecha_oficializacion_desde: Time.parse("2019-04-01T00:00:00-03:00"),
52
+ fecha_oficializacion_hasta: Time.parse("2019-04-30T00:00:00-03:00")
53
+ )
54
+ assert_equal 2, declaraciones.size
55
+ assert declaraciones.any? { |d| d[:identificador_declaracion] == "19092SIMI000313M" }
56
+ assert declaraciones.any? { |d| d[:identificador_declaracion] == "19092SIMI000314N" }
57
+ end
58
+
59
+ def test_detallada_lista_declaraciones_id_inexistente
60
+ savon.expects(:detallada_lista_declaraciones).with(message: :any)
61
+ .returns(fixture("wconsdeclaracion/detallada_lista_declaraciones/por_id_inexistente"))
62
+ error = assert_raises(ResponseError) { ws.detallada_lista_declaraciones identificador_declaracion: "..." }
63
+ assert_equal "21248: Declaracion 19093SIMI000434. inexistente o invalida", error.message
64
+ end
65
+
66
+ def test_detallada_estado
67
+ message = with_auth_section("argIdentificadorDestinacion" => "19093SIMI000434X")
68
+ savon.expects(:detallada_estado).with(message: message)
69
+ .returns(fixture("wconsdeclaracion/detallada_estado/success"))
70
+ r = ws.detallada_estado("19093SIMI000434X")
71
+ assert_hash_includes r, fecha_salida: DateTime.parse("2019-04-25T18:48:12"),
72
+ fecha_cancelacion: DateTime.parse("2019-07-04T02:29:34")
73
+ end
74
+
75
+ private
76
+
77
+ def with_auth_section(msg)
78
+ {
79
+ "argWSAutenticacionEmpresa" => {
80
+ "Token" => "t", "Sign" => "s", "CuitEmpresaConectada" => "23076925089",
81
+ "TipoAgente" => "IMEX", "Rol" => "IMEX"
82
+ }
83
+ }.merge(msg)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WSConstanciaInscripcionTest < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= WSConstanciaInscripcion.new(cuit: "1").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def auth_message
16
+ ta.merge(cuit_representada: "1")
17
+ end
18
+
19
+ def test_dummy
20
+ savon.expects(:dummy).returns(fixture("ws_sr_constancia_inscripcion/dummy/success"))
21
+ assert_equal({ appserver: "OK", dbserver: "OK", authserver: "OK" }, ws.dummy)
22
+ end
23
+
24
+ def test_deberia_devolver_hash_con_datos_generales_y_regimenes_impositivos
25
+ savon.expects(:get_persona)
26
+ .with(message: auth_message.merge(id_persona: "20294834487"))
27
+ .returns(fixture("ws_sr_constancia_inscripcion/get_persona/success"))
28
+ r = ws.get_persona "20294834487"
29
+ assert_hash_includes r[:datos_generales], estado_clave: "ACTIVO", mes_cierre: "6",
30
+ razon_social: "LA REGALERIA S A", tipo_clave: "CUIT", tipo_persona: "JURIDICA"
31
+ assert_hash_includes r[:datos_generales][:domicilio_fiscal], cod_postal: "2300",
32
+ descripcion_provincia: "SANTA FE", direccion: "AV SIEMPRE VIVA 123", localidad: "NUEVA YORK", tipo_domicilio: "FISCAL"
33
+ assert_hash_includes r[:datos_regimen_general][:actividad], id_actividad: "477330", nomenclador: "883",
34
+ orden: "2", periodo: "201311"
35
+ assert_hash_includes r[:datos_regimen_general][:impuesto][1], descripcion_impuesto: "IVA", id_impuesto: "30",
36
+ periodo: "198903"
37
+ assert_hash_includes r[:datos_regimen_general][:regimen], id_impuesto: "208", id_regimen: "159", periodo: "199403"
38
+ end
39
+
40
+ def test_cuando_hay_errores_en_la_constancia_sigue_la_misma_logica
41
+ savon.expects(:get_persona)
42
+ .with(message: auth_message.merge(id_persona: "20294834489"))
43
+ .returns(fixture("ws_sr_constancia_inscripcion/get_persona/failure"))
44
+ r = ws.get_persona "20294834489"
45
+ assert_hash_includes r[:error_regimen_general],
46
+ error: "El contribuyente cuenta con impuestos con baja de oficio por Decreto 1299/98",
47
+ mensaje: "No cumple con las condiciones para enviar datos del regimen general"
48
+ end
49
+
50
+ def test_cuando_no_existe_la_persona
51
+ savon.expects(:get_persona)
52
+ .with(message: auth_message.merge(id_persona: "123"))
53
+ .returns(fixture("ws_sr_constancia_inscripcion/get_persona/fault"))
54
+ error = assert_raises(ServerError) { ws.get_persona "123" }
55
+ assert_match(/No existe persona con ese Id/, error.message)
56
+ end
57
+
58
+ def test_autenticacion_deberia_autenticarse_usando_el_wsaa
59
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
60
+ wss = WSConstanciaInscripcion.new(cuit: "1", cert: "cert", key: "key")
61
+ assert_equal "cert", wss.wsaa.cert
62
+ assert_equal "key", wss.wsaa.key
63
+ assert_equal "ws_sr_constancia_inscripcion", wss.wsaa.service
64
+ wss.wsaa.expects(:login).returns(token: "t", sign: "s")
65
+ savon.expects(:get_persona).with(message: has_path(
66
+ "//token" => "t", "//sign" => "s", "//cuitRepresentada" => "1"
67
+ )).returns(fixture("ws_sr_constancia_inscripcion/get_persona/success"))
68
+ wss.get_persona "20294834487"
69
+ end
70
+
71
+ def test_entorno_development
72
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:development] }.returns(stub(operations: []))
73
+ Client.expects(:new).with do |opts|
74
+ opts[:wsdl] == WSConstanciaInscripcion::WSDL[:development] && opts[:soap_version] == 1
75
+ end.returns(stub(operations: []))
76
+ WSConstanciaInscripcion.new(cuit: "1", env: :development)
77
+ end
78
+
79
+ def test_entorno_production
80
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:production] }.returns(stub(operations: []))
81
+ Client.expects(:new).with do |opts|
82
+ opts[:wsdl] == WSConstanciaInscripcion::WSDL[:production] && opts[:soap_version] == 1
83
+ end.returns(stub(operations: []))
84
+ WSConstanciaInscripcion.new(cuit: "1", env: :production)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WSAATest < TestCase
7
+ def subject
8
+ @subject ||= WSAA.new(wsdl: Arca::WSFE::WSDL[:test])
9
+ end
10
+
11
+ def test_generar_tra_genera_xml
12
+ Time.stubs(:now).returns Time.new(2001, 12, 31, 12, 0, 0, "-03:00")
13
+ xml = subject.generar_tra "wsfe", 2400
14
+ assert_xpath xml, "/loginTicketRequest/header/uniqueId", Time.now.to_i.to_s
15
+ assert_xpath xml, "/loginTicketRequest/header/generationTime", "2001-12-31T11:20:00-03:00"
16
+ assert_xpath xml, "/loginTicketRequest/header/expirationTime", "2001-12-31T12:40:00-03:00"
17
+ assert_xpath xml, "/loginTicketRequest/service", "wsfe"
18
+ end
19
+
20
+ def test_firmar_tra_firma_con_certificado_y_clave
21
+ key = File.read(File.join(__dir__, "test.key"))
22
+ crt = File.read(File.join(__dir__, "test.crt"))
23
+ tra = subject.generar_tra "wsfe", 2400
24
+ assert_match(/BEGIN PKCS7/, subject.firmar_tra(tra, key, crt).to_s)
25
+ end
26
+
27
+ def test_login_manda_tra_al_ws_y_obtiene_ta
28
+ ws = WSAA.new key: "key", cert: "cert", wsdl: Arca::WSFE::WSDL[:test]
29
+ ws.expects(:tra).with("key", "cert", "wsfe", 2400).returns("tra")
30
+ savon.expects(:login_cms).with(message: { in0: "tra" }).returns(fixture("wsaa/login_cms/success"))
31
+ ta = ws.login
32
+ assert_equal "PD94=", ta[:token]
33
+ assert_equal "i9xDN=", ta[:sign]
34
+ assert_equal Time.new(2011, 1, 12, 18, 57, 4, "-03:00"), ta[:generation_time]
35
+ assert_equal Time.new(2011, 1, 13, 6, 57, 4, "-03:00"), ta[:expiration_time]
36
+ end
37
+
38
+ def test_auth_devuelve_hash_con_token_y_sign
39
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
40
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.json")
41
+ Time.stubs(:now).returns(Time.local(2010, 1, 1))
42
+
43
+ ws = WSAA.new(wsdl: Arca::WSFE::WSDL[:test])
44
+ ws.expects(:login).once.returns(token: "token", sign: "sign", expiration_time: Time.now + 60)
45
+ assert_equal({ token: "token", sign: "sign" }, ws.auth)
46
+ end
47
+
48
+ def test_auth_cachea_ta_en_instancia_y_disco
49
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
50
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.json")
51
+ Time.stubs(:now).returns(Time.local(2010, 1, 1))
52
+
53
+ ws = WSAA.new(wsdl: Arca::WSFE::WSDL[:test])
54
+ ta = { token: "token", sign: "sign", generation_time: Time.now, expiration_time: Time.now + 60 }
55
+ ws.expects(:login).once.returns(ta)
56
+ ws.auth
57
+ ws.auth
58
+ assert_same ta, ws.ta
59
+
60
+ ws2 = WSAA.new(wsdl: Arca::WSFE::WSDL[:test])
61
+ ws2.auth
62
+ assert_equal ta[:token], ws2.ta[:token]
63
+ assert_equal ta[:sign], ws2.ta[:sign]
64
+ end
65
+
66
+ def test_si_ta_expiro_ejecuta_solicitar_nuevo
67
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
68
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.json")
69
+ Time.stubs(:now).returns(Time.local(2010, 1, 1))
70
+
71
+ subject.expects(:login).twice
72
+ .returns(token: "t1", expiration_time: Time.now - 2)
73
+ .then.returns(token: "t2")
74
+ subject.auth
75
+ assert_equal "t1", subject.ta[:token]
76
+ subject.auth
77
+ assert_equal "t2", subject.ta[:token]
78
+ end
79
+ end
80
+ end