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,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WSCDCTest < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= WSCDC.new(cuit: "30000000007").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def test_dummy
16
+ savon.expects(:comprobante_dummy).returns(fixture("wscdc/comprobante_dummy/success"))
17
+ assert_equal({ app_server: "OK", db_server: "OK", auth_server: "OK" }, ws.dummy)
18
+ end
19
+
20
+ def test_comprobante_constatar_devuelve_hash_con_resultado_a
21
+ savon.expects(:comprobante_constatar)
22
+ .with(message: {
23
+ auth: ta.merge(cuit: 30_000_000_007),
24
+ cmp_req: {
25
+ cbte_modo: "CAE", cuit_emisor: 20_000_000_001, pto_vta: 1, cbte_tipo: 1, cbte_nro: 2,
26
+ cbte_fch: "20101014", imp_total: 300.8, cod_autorizacion: "60428000005029"
27
+ }
28
+ })
29
+ .returns(fixture("wscdc/comprobante_constatar/success"))
30
+ r = ws.comprobante_constatar(
31
+ cbte_modo: "CAE", cuit_emisor: 20_000_000_001, pto_vta: 1, cbte_tipo: 1, cbte_nro: 2,
32
+ cbte_fch: "20101014", imp_total: 300.8, cod_autorizacion: "60428000005029"
33
+ )
34
+ assert_equal "A", r[:resultado]
35
+ assert r[:cmp_resp].present?
36
+ assert_equal "20130729204436", r[:fch_proceso]
37
+ end
38
+
39
+ def test_comprobante_constatar_con_errores_levanta_response_error
40
+ savon.expects(:comprobante_constatar).with(message: :any).returns(fixture("wscdc/comprobante_constatar/with_errors"))
41
+ error = assert_raises(ResponseError) do
42
+ ws.comprobante_constatar(cbte_modo: "CAE", cuit_emisor: 2_222_222_222_222, pto_vta: 1, cbte_tipo: 1,
43
+ cbte_nro: 2, cbte_fch: "20101014", imp_total: 300.8, cod_autorizacion: "60428000005029")
44
+ end
45
+ assert_equal [ { code: "2", msg: "El campo CuitEmisor es invalido." } ], error.errors
46
+ end
47
+
48
+ def test_comprobantes_modalidad_consultar
49
+ savon.expects(:comprobantes_modalidad_consultar)
50
+ .with(message: { auth: ta.merge(cuit: 30_000_000_007) })
51
+ .returns(fixture("wscdc/comprobantes_modalidad_consultar/success"))
52
+ r = ws.comprobantes_modalidad_consultar
53
+ assert_equal 3, r.size
54
+ assert_hash_includes r[0], cod: "CAE", desc: "Codigo de Autorizacion Electronico"
55
+ assert_equal "CAEA", r[1][:cod]
56
+ assert_equal "CAI", r[2][:cod]
57
+ end
58
+
59
+ def test_comprobantes_tipo_consultar
60
+ savon.expects(:comprobantes_tipo_consultar)
61
+ .with(message: { auth: ta.merge(cuit: 30_000_000_007) })
62
+ .returns(fixture("wscdc/comprobantes_tipo_consultar/success"))
63
+ r = ws.comprobantes_tipo_consultar
64
+ assert_equal 2, r.size
65
+ assert_hash_includes r[0], id: 1, desc: "Factura A", fch_desde: Date.new(2010, 9, 17)
66
+ assert_equal 6, r[1][:id]
67
+ end
68
+
69
+ def test_documentos_tipo_consultar
70
+ savon.expects(:documentos_tipo_consultar)
71
+ .with(message: { auth: ta.merge(cuit: 30_000_000_007) })
72
+ .returns(fixture("wscdc/documentos_tipo_consultar/success"))
73
+ r = ws.documentos_tipo_consultar
74
+ assert_equal 1, r.size
75
+ assert_hash_includes r[0], id: 80, desc: "CUIT", fch_desde: Date.new(2008, 7, 25)
76
+ end
77
+
78
+ def test_opcionales_tipo_consultar
79
+ savon.expects(:opcionales_tipo_consultar)
80
+ .with(message: { auth: ta.merge(cuit: 30_000_000_007) })
81
+ .returns(fixture("wscdc/opcionales_tipo_consultar/success"))
82
+ r = ws.opcionales_tipo_consultar
83
+ assert_equal 1, r.size
84
+ assert_hash_includes r[0], id: "OP1", desc: "Opcional tipo 1"
85
+ end
86
+
87
+ def test_entorno_development
88
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:development] }.returns(stub(operations: []))
89
+ Client.expects(:new).with do |opts|
90
+ opts[:wsdl] == WSCDC::WSDL[:development] && opts[:soap_version] == 1
91
+ end.returns(stub(operations: []))
92
+ WSCDC.new(cuit: "1", env: :development)
93
+ end
94
+
95
+ def test_entorno_production
96
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:production] }.returns(stub(operations: []))
97
+ Client.expects(:new).with do |opts|
98
+ opts[:wsdl] == WSCDC::WSDL[:production] && opts[:soap_version] == 1
99
+ end.returns(stub(operations: []))
100
+ WSCDC.new(cuit: "1", env: :production)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,319 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WSFETest < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def ws
12
+ @ws ||= WSFE.new(cuit: "1").tap { |w| w.wsaa.stubs auth: ta }
13
+ end
14
+
15
+ def auth
16
+ { auth: ta.merge(cuit: "1") }
17
+ end
18
+
19
+ def test_dummy
20
+ savon.expects(:fe_dummy).returns(fixture("wsfe/fe_dummy/success"))
21
+ assert_equal({ app_server: "OK", db_server: "OK", auth_server: "OK" }, ws.dummy)
22
+ end
23
+
24
+ def test_tipos_comprobantes
25
+ savon.expects(:fe_param_get_tipos_cbte).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_cbte/success"))
26
+ assert_equal [
27
+ { id: 1, desc: "Factura A", fch_desde: Date.new(2010, 9, 17), fch_hasta: nil },
28
+ { id: 2, desc: "Nota de Débito A", fch_desde: Date.new(2010, 9, 18), fch_hasta: Date.new(2011, 9, 18) }
29
+ ], ws.tipos_comprobantes
30
+ end
31
+
32
+ def test_tipos_documentos
33
+ savon.expects(:fe_param_get_tipos_doc).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_doc/success"))
34
+ assert_equal [ { id: 80, desc: "CUIT", fch_desde: Date.new(2008, 7, 25), fch_hasta: nil } ], ws.tipos_documentos
35
+ end
36
+
37
+ def test_tipos_concepto
38
+ savon.expects(:fe_param_get_tipos_concepto).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_concepto/success"))
39
+ assert_equal [ { id: 1, desc: "Producto", fch_desde: Date.new(2008, 7, 25), fch_hasta: nil } ], ws.tipos_concepto
40
+ end
41
+
42
+ def test_tipos_monedas
43
+ savon.expects(:fe_param_get_tipos_monedas).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_monedas/success"))
44
+ assert_equal [
45
+ { id: "PES", desc: "Pesos Argentinos", fch_desde: Date.new(2009, 4, 3), fch_hasta: nil },
46
+ { id: "002", desc: "Dólar Libre EEUU", fch_desde: Date.new(2009, 4, 16), fch_hasta: nil }
47
+ ], ws.tipos_monedas
48
+ end
49
+
50
+ def test_tipos_opcional
51
+ savon.expects(:fe_param_get_tipos_opcional).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_opcional/success"))
52
+ assert_equal [], ws.tipos_opcional
53
+ end
54
+
55
+ def test_tipos_iva
56
+ savon.expects(:fe_param_get_tipos_iva).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_iva/success"))
57
+ assert_equal [ { id: 5, desc: "21%", fch_desde: Date.new(2009, 2, 20), fch_hasta: nil } ], ws.tipos_iva
58
+ end
59
+
60
+ def test_tipos_tributos
61
+ savon.expects(:fe_param_get_tipos_tributos).with(message: auth).returns(fixture("wsfe/fe_param_get_tipos_tributos/success"))
62
+ assert_equal [ { id: 2, desc: "Impuestos provinciales", fch_desde: Date.new(2010, 9, 17), fch_hasta: nil } ],
63
+ ws.tipos_tributos
64
+ end
65
+
66
+ def test_puntos_venta
67
+ savon.expects(:fe_param_get_ptos_venta).with(message: auth).returns(fixture("wsfe/fe_param_get_ptos_venta/success"))
68
+ assert_equal [
69
+ { nro: 1, emision_tipo: "CAE", bloqueado: false, fch_baja: nil },
70
+ { nro: 2, emision_tipo: "CAEA", bloqueado: true, fch_baja: Date.new(2011, 1, 31) }
71
+ ], ws.puntos_venta
72
+ end
73
+
74
+ def test_cotizacion_cuando_la_moneda_existe
75
+ savon.expects(:fe_param_get_cotizacion).with(message: auth.merge(mon_id: "DOL")).returns(fixture("wsfe/fe_param_get_cotizacion/dolar"))
76
+ assert_equal 3.976, ws.cotizacion("DOL")
77
+ end
78
+
79
+ def test_cotizacion_cuando_la_moneda_no_existe
80
+ savon.expects(:fe_param_get_cotizacion).with(message: auth.merge(mon_id: "PES")).returns(fixture("wsfe/fe_param_get_cotizacion/inexistente"))
81
+ e = assert_raises(ResponseError) { ws.cotizacion("PES") }
82
+ assert_match(/602: Sin Resultados/, e.message)
83
+ assert e.code?(602)
84
+ refute e.code?(603)
85
+ end
86
+
87
+ def test_cant_max_registros_x_lote
88
+ savon.expects(:fe_comp_tot_x_request).with(message: auth).returns(fixture("wsfe/fe_comp_tot_x_request/success"))
89
+ assert_equal 250, ws.cant_max_registros_x_lote
90
+ end
91
+
92
+ def test_autorizar_comprobantes_devuelve_hash_con_cae
93
+ savon.expects(:fecae_solicitar).with(message: has_path(
94
+ "//Auth/Token" => "t", "//FeCAEReq/FeCabReq/CantReg" => 1, "//FeCAEReq/FeCabReq/PtoVta" => 2,
95
+ "//FeCAEReq/FeCabReq/CbteTipo" => 1,
96
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/DocTipo" => 80,
97
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/DocNro" => 30_521_189_203,
98
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteFch" => 20_110_113,
99
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/ImpTotal" => 1270.48,
100
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/ImpIVA" => 220.5,
101
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Id" => 5,
102
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Importe" => 220.5,
103
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Id" => 0,
104
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/BaseImp" => 150,
105
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Alic" => 5.2,
106
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Importe" => 7.8
107
+ )).returns(fixture("wsfe/fecae_solicitar/autorizacion_1_cbte"))
108
+ rta = ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [ {
109
+ cbte_nro: 1, concepto: 1, doc_nro: 30_521_189_203, doc_tipo: 80, cbte_fch: Date.new(2011, 0o1, 13),
110
+ imp_total: 1270.48, imp_neto: 1049.98, imp_iva: 220.50, mon_id: "PES", mon_cotiz: 1,
111
+ iva: { alic_iva: [ { id: 5, base_imp: 1049.98, importe: 220.50 } ] },
112
+ tributos: { tributo: [ { id: 0, base_imp: 150, alic: 5.2, importe: 7.8 } ] }
113
+ } ])
114
+ assert_hash_includes rta[0], cae: "61023008595705", cae_fch_vto: Date.new(2011, 0o1, 23), cbte_nro: 1,
115
+ resultado: "A", observaciones: []
116
+ assert_equal 1, rta.size
117
+ end
118
+
119
+ def test_autorizar_comprobantes_con_varias_alicuotas_iva
120
+ savon.expects(:fecae_solicitar).with(message: has_path(
121
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Id" => 5,
122
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Importe" => 21,
123
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[2]/Id" => 4,
124
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[2]/Importe" => 5.25
125
+ )).returns(fixture("wsfe/fecae_solicitar/autorizacion_1_cbte"))
126
+ ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [ { iva: { alic_iva: [
127
+ { id: 5, base_imp: 100, importe: 21 },
128
+ { id: 4, base_imp: 50, importe: 5.25 }
129
+ ] } } ])
130
+ end
131
+
132
+ def test_autorizar_comprobantes_con_varios_comprobantes
133
+ savon.expects(:fecae_solicitar).with(message: has_path(
134
+ "//FeCAEReq/FeCabReq/CantReg" => 2,
135
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteDesde" => 5, "//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteHasta" => 5,
136
+ "//FeCAEReq/FeDetReq/FECAEDetRequest[2]/CbteDesde" => 6, "//FeCAEReq/FeDetReq/FECAEDetRequest[2]/CbteHasta" => 6
137
+ )).returns(fixture("wsfe/fecae_solicitar/autorizacion_2_cbtes"))
138
+ rta = ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [ { cbte_nro: 5 }, { cbte_nro: 6 } ])
139
+ assert_hash_includes rta[0], cbte_nro: 5, cae: "61033008894096"
140
+ assert_hash_includes rta[1], cbte_nro: 6, cae: "61033008894101"
141
+ end
142
+
143
+ def test_autorizar_comprobantes_con_2_observaciones
144
+ savon.expects(:fecae_solicitar).with(message: :any).returns(fixture("wsfe/fecae_solicitar/dos_observaciones"))
145
+ rta = ws.autorizar_comprobantes comprobantes: []
146
+ assert_hash_includes rta[0], cbte_nro: 3, cae: nil, resultado: "R",
147
+ observaciones: [ { code: 10_048, msg: "Msg 1" }, { code: 10_018, msg: "Msg 2" } ]
148
+ end
149
+
150
+ def test_autorizar_comprobantes_con_1_observacion
151
+ savon.expects(:fecae_solicitar).with(message: :any).returns(fixture("wsfe/fecae_solicitar/una_observacion"))
152
+ rta = ws.autorizar_comprobantes comprobantes: []
153
+ assert_hash_includes rta[0], observaciones: [ { code: 10_048, msg: "Msg 1" } ]
154
+ end
155
+
156
+ def test_solicitar_caea_manda_periodo_y_orden
157
+ Date.stubs today: Date.new(2011, 1, 27)
158
+ savon.expects(:fecaea_solicitar).with(message: has_path("//Periodo" => "201102",
159
+ "//Orden" => 1)).returns(fixture("wsfe/fecaea_solicitar/success"))
160
+ assert_hash_includes ws.solicitar_caea,
161
+ caea: "21043476341977", fch_tope_inf: Date.new(2011, 0o3, 17),
162
+ fch_vig_desde: Date.new(2011, 0o2, 0o1), fch_vig_hasta: Date.new(2011, 0o2, 15)
163
+ end
164
+
165
+ def test_periodo_para_solicitud_caea_primer_quincena
166
+ Date.stubs today: Date.new(2011, 1, 12)
167
+ assert_equal({ periodo: "201101", orden: 2 }, ws.periodo_para_solicitud_caea)
168
+ Date.stubs today: Date.new(2011, 1, 15)
169
+ assert_equal({ periodo: "201101", orden: 2 }, ws.periodo_para_solicitud_caea)
170
+ end
171
+
172
+ def test_periodo_para_solicitud_caea_segunda_quincena
173
+ Date.stubs today: Date.new(2011, 1, 16)
174
+ assert_equal({ periodo: "201102", orden: 1 }, ws.periodo_para_solicitud_caea)
175
+ Date.stubs today: Date.new(2011, 1, 31)
176
+ assert_equal({ periodo: "201102", orden: 1 }, ws.periodo_para_solicitud_caea)
177
+ end
178
+
179
+ def test_solicitar_caea_cuando_ya_otorgado_consulta_y_devuelve
180
+ Date.stubs today: Date.new(2011, 1, 27)
181
+ savon.expects(:fecaea_solicitar).with(message: has_path("//Periodo" => "201102",
182
+ "//Orden" => 1)).returns(fixture("wsfe/fecaea_solicitar/caea_ya_otorgado"))
183
+ savon.expects(:fecaea_consultar).with(message: has_path("//Periodo" => "201102",
184
+ "//Orden" => 1)).returns(fixture("wsfe/fecaea_consultar/success"))
185
+ assert_hash_includes ws.solicitar_caea, caea: "21043476341977", fch_vig_desde: Date.new(2011, 0o2, 0o1)
186
+ end
187
+
188
+ def test_solicitar_caea_encapsula_errores
189
+ savon.expects(:fecaea_solicitar).with(message: :any).returns(fixture("wsfe/fecaea_solicitar/error_distinto"))
190
+ assert_raises(ResponseError) { ws.solicitar_caea }
191
+ end
192
+
193
+ def test_informar_comprobantes_caea
194
+ savon.expects(:fecaea_reg_informativo).with(message: has_path(
195
+ "//Auth/Token" => "t", "//FeCAEARegInfReq/FeCabReq/CantReg" => 2,
196
+ "//FeCAEARegInfReq/FeCabReq/PtoVta" => 3, "//FeCAEARegInfReq/FeCabReq/CbteTipo" => 1,
197
+ "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CbteDesde" => 1, "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CbteHasta" => 1,
198
+ "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CAEA" => "21043476341977",
199
+ "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CbteDesde" => 2, "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CbteHasta" => 2,
200
+ "//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CAEA" => "21043476341977"
201
+ )).returns(fixture("wsfe/fecaea_reg_informativo/informe_rtdo_parcial"))
202
+ rta = ws.informar_comprobantes_caea(cbte_tipo: 1, pto_vta: 3, comprobantes: [
203
+ { cbte_nro: 1, caea: "21043476341977" }, { cbte_nro: 2, caea: "21043476341977" }
204
+ ])
205
+ assert_hash_includes rta[0], cbte_nro: 1, caea: "21043476341977", resultado: "A", observaciones: []
206
+ assert_hash_includes rta[1], cbte_nro: 2, caea: "21043476341977", resultado: "R",
207
+ observaciones: [ { code: 724, msg: "Msg" } ]
208
+ end
209
+
210
+ def test_informar_caea_sin_movimientos
211
+ savon.expects(:fecaea_sin_movimiento_informar).with(message: has_path(
212
+ "//Auth/Token" => "t", "//PtoVta" => 4, "//CAEA" => "21043476341977"
213
+ )).returns(fixture("wsfe/fecaea_sin_movimiento_informar/success"))
214
+ rta = ws.informar_caea_sin_movimientos("21043476341977", 4)
215
+ assert_hash_includes rta, caea: "21043476341977", resultado: "A"
216
+ end
217
+
218
+ def test_consultar_caea
219
+ savon.expects(:fecaea_consultar).with(message: has_path("//Periodo" => "201101",
220
+ "//Orden" => 1)).returns(fixture("wsfe/fecaea_consultar/success"))
221
+ assert_hash_includes ws.consultar_caea(Date.new(2011, 1, 1)), caea: "21043476341977",
222
+ fch_tope_inf: Date.new(2011, 0o3, 17)
223
+ end
224
+
225
+ def test_ultimo_comprobante_autorizado
226
+ savon.expects(:fe_comp_ultimo_autorizado).with(message: has_path("//PtoVta" => 1,
227
+ "//CbteTipo" => 1)).returns(fixture("wsfe/fe_comp_ultimo_autorizado/success"))
228
+ assert_equal 20, ws.ultimo_comprobante_autorizado(pto_vta: 1, cbte_tipo: 1)
229
+ end
230
+
231
+ def test_consultar_comprobante
232
+ savon.expects(:fe_comp_consultar).with(message: has_path(
233
+ "//Auth/Token" => "t", "//FeCompConsReq/PtoVta" => 1, "//FeCompConsReq/CbteTipo" => 2, "//FeCompConsReq/CbteNro" => 3
234
+ )).returns(fixture("wsfe/fe_comp_consultar/success"))
235
+ rta = ws.consultar_comprobante(pto_vta: 1, cbte_tipo: 2, cbte_nro: 3)
236
+ assert_equal "61023008595705", rta[:cod_autorizacion]
237
+ assert_equal "CAE", rta[:emision_tipo]
238
+ end
239
+
240
+ def test_autenticacion_deberia_autenticarse_usando_el_wsaa
241
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
242
+ wsfe = WSFE.new cuit: "1", cert: "cert", key: "key"
243
+ assert_equal "cert", wsfe.wsaa.cert
244
+ assert_equal "key", wsfe.wsaa.key
245
+ assert_equal "wsfe", wsfe.wsaa.service
246
+ wsfe.wsaa.expects(:login).returns(token: "t", sign: "s")
247
+ savon.expects(:fe_param_get_tipos_cbte).with(message: has_path(
248
+ "//Auth/Token" => "t", "//Auth/Sign" => "s", "//Auth/Cuit" => "1"
249
+ )).returns(fixture("wsfe/fe_param_get_tipos_cbte/success"))
250
+ wsfe.tipos_comprobantes
251
+ end
252
+
253
+ def test_entorno_development
254
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:development] }.returns(stub(operations: []))
255
+ Client.expects(:new).with do |opts|
256
+ opts[:wsdl] == WSFE::WSDL[:development] && opts[:convert_request_keys_to] == :camelcase
257
+ end.returns(stub(operations: []))
258
+ WSFE.new env: :development
259
+ end
260
+
261
+ def test_entorno_production
262
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:production] }.returns(stub(operations: []))
263
+ Client.expects(:new).with do |opts|
264
+ opts[:wsdl] == WSFE::WSDL[:production] && opts[:convert_request_keys_to] == :camelcase
265
+ end.returns(stub(operations: []))
266
+ WSFE.new env: "production"
267
+ end
268
+
269
+ def test_manejo_de_errores_cuando_hay_un_error
270
+ savon.expects(:fe_param_get_tipos_cbte).with(message: :any).returns(fixture("wsfe/fe_param_get_tipos_cbte/failure_1_error"))
271
+ e = assert_raises(ResponseError) { ws.tipos_comprobantes }
272
+ assert_equal [ { code: "600", msg: "No se corresponden token con firma" } ], e.errors
273
+ assert_equal "600: No se corresponden token con firma", e.message
274
+ end
275
+
276
+ def test_manejo_de_errores_cuando_hay_varios_errores
277
+ savon.expects(:fe_param_get_tipos_cbte).with(message: :any).returns(fixture("wsfe/fe_param_get_tipos_cbte/failure_2_errors"))
278
+ e = assert_raises(ResponseError) { ws.tipos_comprobantes }
279
+ assert_equal [
280
+ { code: "600", msg: "No se corresponden token con firma" },
281
+ { code: "601", msg: "CUIT representada no incluida en token" }
282
+ ], e.errors
283
+ assert_equal "600: No se corresponden token con firma; 601: CUIT representada no incluida en token", e.message
284
+ end
285
+
286
+ def test_periodo_para_consulta_caea
287
+ assert_equal({ periodo: "201101", orden: 1 }, ws.periodo_para_consulta_caea(Date.new(2011, 1, 1)))
288
+ assert_equal({ periodo: "201101", orden: 1 }, ws.periodo_para_consulta_caea(Date.new(2011, 1, 15)))
289
+ assert_equal({ periodo: "201101", orden: 2 }, ws.periodo_para_consulta_caea(Date.new(2011, 1, 16)))
290
+ assert_equal({ periodo: "201101", orden: 2 }, ws.periodo_para_consulta_caea(Date.new(2011, 1, 31)))
291
+ assert_equal({ periodo: "201102", orden: 1 }, ws.periodo_para_consulta_caea(Date.new(2011, 2, 2)))
292
+ end
293
+
294
+ def test_fecha_inicio_quincena_siguiente
295
+ assert_equal Date.new(2010, 1, 16), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 1))
296
+ assert_equal Date.new(2010, 1, 16), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 10))
297
+ assert_equal Date.new(2010, 1, 16), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 15))
298
+ assert_equal Date.new(2010, 2, 1), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 16))
299
+ assert_equal Date.new(2010, 2, 1), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 20))
300
+ assert_equal Date.new(2010, 2, 1), fecha_inicio_quincena_siguiente(Date.new(2010, 1, 31))
301
+ assert_equal Date.new(2011, 1, 1), fecha_inicio_quincena_siguiente(Date.new(2010, 12, 31))
302
+ end
303
+
304
+ def test_comprobante_to_request_no_envia_tributos_si_imp_trib_es_0
305
+ refute c2r({ imp_trib: 0.0, tributos: { tributo: [] } }, {}).key?(:tributos)
306
+ end
307
+
308
+ private
309
+
310
+ def fecha_inicio_quincena_siguiente(fecha)
311
+ Date.stubs(today: fecha)
312
+ ws.fecha_inicio_quincena_siguiente
313
+ end
314
+
315
+ def c2r(comprobante, opciones)
316
+ ws.comprobante_to_request comprobante, opciones
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ module Arca
6
+ class WSFeCredTest < TestCase
7
+ def ta
8
+ @ta ||= { token: "t", sign: "s" }
9
+ end
10
+
11
+ def cuit
12
+ "20123456789"
13
+ end
14
+
15
+ def cuit_normalized
16
+ 20_123_456_789
17
+ end
18
+
19
+ def ws
20
+ @ws ||= WSFeCred.new(cuit: cuit).tap { |w| w.wsaa.stubs auth: ta }
21
+ end
22
+
23
+ def auth_request
24
+ { auth_request: ta.merge(cuit_representada: cuit_normalized) }
25
+ end
26
+
27
+ def test_dummy
28
+ savon.expects(:dummy).returns(fixture("wsfecred/dummy/success"))
29
+ assert_equal({ app_server: "OK", auth_server: "OK", db_server: "OK" }, ws.dummy)
30
+ end
31
+
32
+ def test_consultar_tipos_retenciones
33
+ savon.expects(:consultar_tipos_retenciones).with(message: auth_request).returns(fixture("wsfecred/consultar_tipos_retenciones/success"))
34
+ rta = ws.consultar_tipos_retenciones
35
+ assert_instance_of Array, rta
36
+ assert_operator rta.size, :>=, 1
37
+ assert_hash_includes rta.first, codigo: "1", descripcion: "Retención 1"
38
+ end
39
+
40
+ def test_consultar_tipos_motivos_rechazo
41
+ savon.expects(:consultar_tipos_motivos_rechazo).with(message: auth_request).returns(fixture("wsfecred/consultar_tipos_motivos_rechazo/success"))
42
+ rta = ws.consultar_tipos_motivos_rechazo
43
+ assert_instance_of Array, rta
44
+ assert_operator rta.size, :>=, 1
45
+ assert_hash_includes rta.first, codigo: "1", descripcion: "Motivo rechazo 1"
46
+ end
47
+
48
+ def test_consultar_tipos_formas_cancelacion
49
+ savon.expects(:consultar_tipos_formas_cancelacion).with(message: auth_request).returns(fixture("wsfecred/consultar_tipos_formas_cancelacion/success"))
50
+ rta = ws.consultar_tipos_formas_cancelacion
51
+ assert_instance_of Array, rta
52
+ assert_operator rta.size, :>=, 1
53
+ assert_hash_includes rta.first, codigo: "1", descripcion: "Forma cancelación 1"
54
+ end
55
+
56
+ def test_consultar_cta_cte_con_cod_cta_cte
57
+ savon.expects(:consultar_cta_cte).with(message: auth_request.merge(id_cta_cte: { cod_cta_cte: 12_345 })).returns(fixture("wsfecred/consultar_cta_cte/success"))
58
+ rta = ws.consultar_cta_cte(cod_cta_cte: 12_345)
59
+ assert_instance_of Hash, rta
60
+ assert rta.key?(:cta_cte)
61
+ assert rta.key?(:array_observaciones)
62
+ end
63
+
64
+ def test_consultar_comprobantes_con_rol
65
+ savon.expects(:consultar_comprobantes).with(message: auth_request.merge(rol_cuit_representada: "Emisor")).returns(fixture("wsfecred/consultar_comprobantes/success"))
66
+ rta = ws.consultar_comprobantes(rol_cuit_representada: "Emisor")
67
+ assert rta.key?(:array_comprobantes)
68
+ assert rta.key?(:nro_pagina)
69
+ assert rta.key?(:hay_mas)
70
+ assert_instance_of Array, rta[:array_comprobantes]
71
+ end
72
+
73
+ def test_consultar_ctas_ctes_con_rol
74
+ savon.expects(:consultar_ctas_ctes).with(message: auth_request.merge(rol_cuit_representada: "Receptor")).returns(fixture("wsfecred/consultar_ctas_ctes/success"))
75
+ rta = ws.consultar_ctas_ctes(rol_cuit_representada: "Receptor")
76
+ assert rta.key?(:array_infos_cta_cte)
77
+ assert rta.key?(:nro_pagina)
78
+ assert rta.key?(:hay_mas)
79
+ assert_instance_of Array, rta[:array_infos_cta_cte]
80
+ end
81
+
82
+ def test_aceptar_f_e_cred
83
+ savon.expects(:aceptar_fe_cred).with(message: has_path(
84
+ "//AuthRequest/Token" => "t",
85
+ "//IdCtaCte/CodCtaCte" => 12_345
86
+ )).returns(fixture("wsfecred/aceptar_f_e_cred/success"))
87
+ rta = ws.aceptar_f_e_cred(
88
+ { cod_cta_cte: 12_345 },
89
+ saldo_aceptado: 100, cod_moneda: "PES", cotizacion_moneda_ult: 1.0
90
+ )
91
+ assert rta.key?(:resultado)
92
+ assert rta.key?(:id_cta_cte)
93
+ assert_equal "A", rta[:resultado]
94
+ end
95
+
96
+ def test_rechaza_id_cta_cte_invalido
97
+ assert_raises(ArgumentError) { ws.send(:build_id_cta_cte, {}) }
98
+ assert_raises(ArgumentError) { ws.send(:build_id_cta_cte, 123) }
99
+ end
100
+
101
+ def test_rechaza_id_comprobante_sin_claves
102
+ assert_raises(ArgumentError) { ws.send(:build_id_comprobante, {}) }
103
+ assert_raises(ArgumentError) { ws.send(:build_id_comprobante, { cuit_emisor: 1 }) }
104
+ end
105
+
106
+ def test_rechaza_array_motivos_rechazo_vacio_en_rechazar_f_e_cred
107
+ error = assert_raises(ArgumentError) { ws.rechazar_f_e_cred({ cod_cta_cte: 1 }, array_motivos_rechazo: []) }
108
+ assert_match(/array_motivos_rechazo must have at least one motive/, error.message)
109
+ end
110
+
111
+ def test_rechaza_array_motivos_rechazo_vacio_en_rechazar_nota_dc
112
+ error = assert_raises(ArgumentError) do
113
+ ws.rechazar_nota_dc({ cuit_emisor: 1, cod_tipo_cmp: 1, pto_vta: 1, nro_cmp: 1 }, array_motivos_rechazo: [])
114
+ end
115
+ assert_match(/array_motivos_rechazo must have at least one motive/, error.message)
116
+ end
117
+
118
+ def test_rechaza_array_formas_cancelacion_vacio
119
+ error = assert_raises(ArgumentError) do
120
+ ws.informar_cancelacion_total_f_e_cred({ cod_cta_cte: 1 }, array_formas_cancelacion: [],
121
+ importe_cancelacion: 100)
122
+ end
123
+ assert_match(/array_formas_cancelacion must have at least one item/, error.message)
124
+ end
125
+
126
+ def test_autenticacion_deberia_autenticarse_usando_el_wsaa
127
+ FileUtils.rm_rf Dir.glob("tmp/*-test-*-ta.dump")
128
+ wsfecred = WSFeCred.new(cuit: "1", cert: "cert", key: "key")
129
+ assert_equal "cert", wsfecred.wsaa.cert
130
+ assert_equal "key", wsfecred.wsaa.key
131
+ assert_equal "wsfecred", wsfecred.wsaa.service
132
+ wsfecred.wsaa.expects(:login).returns(token: "t", sign: "s")
133
+ savon.expects(:consultar_tipos_retenciones).with(message: has_path(
134
+ "//AuthRequest/Token" => "t", "//AuthRequest/Sign" => "s", "//AuthRequest/CuitRepresentada" => 1
135
+ )).returns(fixture("wsfecred/consultar_tipos_retenciones/success"))
136
+ wsfecred.consultar_tipos_retenciones
137
+ end
138
+
139
+ def test_cuando_hay_un_error_en_la_respuesta
140
+ savon.expects(:consultar_tipos_retenciones).with(message: :any).returns(fixture("wsfecred/consultar_tipos_retenciones/failure"))
141
+ e = assert_raises(ResponseError) { ws.consultar_tipos_retenciones }
142
+ assert_match(/600/, e.message)
143
+ assert e.code?("600")
144
+ end
145
+
146
+ def test_entorno_development
147
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:development] }.returns(stub(operations: []))
148
+ Client.expects(:new).with do |opts|
149
+ opts[:wsdl] == WSFeCred::WSDL[:development] && opts[:soap_version] == 1 && opts[:convert_request_keys_to] == :camelcase
150
+ end.returns(stub(operations: []))
151
+ WSFeCred.new(cuit: "1", env: :development)
152
+ end
153
+
154
+ def test_entorno_production
155
+ Client.expects(:new).with { |opts| opts[:wsdl] == WSAA::WSDL[:production] }.returns(stub(operations: []))
156
+ Client.expects(:new).with do |opts|
157
+ opts[:wsdl] == WSFeCred::WSDL[:production] && opts[:soap_version] == 1 && opts[:convert_request_keys_to] == :camelcase
158
+ end.returns(stub(operations: []))
159
+ WSFeCred.new(cuit: "1", env: "production")
160
+ end
161
+ end
162
+ end