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.
- checksums.yaml +7 -0
- data/.devcontainer/Dockerfile +8 -0
- data/.devcontainer/devcontainer.json +12 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/ci.yml +16 -0
- data/.github/workflows/release.yml +37 -0
- data/.gitignore +8 -0
- data/.mise.toml +2 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +19 -0
- data/CONTRIBUTING.md +48 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +209 -0
- data/Rakefile +10 -0
- data/SECURITY.md +14 -0
- data/arca.gemspec +40 -0
- data/bin/console +7 -0
- data/lib/arca/client.rb +29 -0
- data/lib/arca/core_ext/hash.rb +13 -0
- data/lib/arca/errors/error.rb +13 -0
- data/lib/arca/errors/network_error.rb +15 -0
- data/lib/arca/errors/response_error.rb +18 -0
- data/lib/arca/errors/server_error.rb +6 -0
- data/lib/arca/persona_service_a100.rb +51 -0
- data/lib/arca/persona_service_a4.rb +34 -0
- data/lib/arca/persona_service_a5.rb +46 -0
- data/lib/arca/type_conversions.rb +44 -0
- data/lib/arca/version.rb +5 -0
- data/lib/arca/w_cons_declaracion.rb +66 -0
- data/lib/arca/ws_constancia_inscripcion.rb +34 -0
- data/lib/arca/wsaa.rb +140 -0
- data/lib/arca/wscdc.rb +149 -0
- data/lib/arca/wsfe.rb +205 -0
- data/lib/arca/wsfecred.rb +438 -0
- data/lib/arca/wsrgiva.rb +72 -0
- data/lib/arca.rb +31 -0
- data/test/arca/client_test.rb +43 -0
- data/test/arca/core_ext/hash_test.rb +15 -0
- data/test/arca/persona_service_a100_test.rb +45 -0
- data/test/arca/persona_service_a4_test.rb +31 -0
- data/test/arca/persona_service_a5_test.rb +31 -0
- data/test/arca/test.crt +19 -0
- data/test/arca/test.key +28 -0
- data/test/arca/type_conversions_test.rb +43 -0
- data/test/arca/w_cons_declaracion_test.rb +86 -0
- data/test/arca/ws_constancia_inscripcion_test.rb +87 -0
- data/test/arca/wsaa_test.rb +80 -0
- data/test/arca/wscdc_test.rb +103 -0
- data/test/arca/wsfe_test.rb +319 -0
- data/test/arca/wsfecred_test.rb +162 -0
- data/test/arca/wsrgiva_test.rb +91 -0
- data/test/fixtures/wconsdeclaracion/detallada_estado/success.xml +24 -0
- data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_fecha_success.xml +39 -0
- data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_id_inexistente.xml +16 -0
- data/test/fixtures/wconsdeclaracion/detallada_lista_declaraciones/por_id_success.xml +29 -0
- data/test/fixtures/wconsdeclaracion/dummy/success.xml +12 -0
- data/test/fixtures/wconsdeclaracion/wconsdeclaracion.wsdl +2976 -0
- data/test/fixtures/ws_sr_constancia_inscripcion/dummy/success.xml +11 -0
- data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/failure.xml +35 -0
- data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/fault.xml +8 -0
- data/test/fixtures/ws_sr_constancia_inscripcion/get_persona/success.xml +53 -0
- data/test/fixtures/ws_sr_constancia_inscripcion/ws_constancia_inscripcion.wsdl +230 -0
- data/test/fixtures/ws_sr_padron_a100/company_types/success.xml +23 -0
- data/test/fixtures/ws_sr_padron_a100/dummy/success.xml +11 -0
- data/test/fixtures/ws_sr_padron_a100/jurisdictions/success.xml +31 -0
- data/test/fixtures/ws_sr_padron_a100/public_organisms/success.xml +23 -0
- data/test/fixtures/ws_sr_padron_a100.wsdl +125 -0
- data/test/fixtures/ws_sr_padron_a4/dummy/success.xml +11 -0
- data/test/fixtures/ws_sr_padron_a4/get_persona/success.xml +133 -0
- data/test/fixtures/ws_sr_padron_a4.wsdl +229 -0
- data/test/fixtures/ws_sr_padron_a5/dummy/success.xml +11 -0
- data/test/fixtures/ws_sr_padron_a5/get_persona/success.xml +62 -0
- data/test/fixtures/ws_sr_padron_a5.wsdl +283 -0
- data/test/fixtures/wsaa/login_cms/fault.xml +12 -0
- data/test/fixtures/wsaa/login_cms/success.xml +16 -0
- data/test/fixtures/wsaa/login_cms/token_expirado.xml +14 -0
- data/test/fixtures/wsaa/wsaa.wsdl +103 -0
- data/test/fixtures/wscdc/comprobante_constatar/success.xml +22 -0
- data/test/fixtures/wscdc/comprobante_constatar/with_errors.xml +28 -0
- data/test/fixtures/wscdc/comprobante_dummy/success.xml +11 -0
- data/test/fixtures/wscdc/comprobantes_modalidad_consultar/success.xml +22 -0
- data/test/fixtures/wscdc/comprobantes_tipo_consultar/success.xml +22 -0
- data/test/fixtures/wscdc/documentos_tipo_consultar/success.xml +16 -0
- data/test/fixtures/wscdc/opcionales_tipo_consultar/success.xml +14 -0
- data/test/fixtures/wscdc/wscdc.wsdl +305 -0
- data/test/fixtures/wsfe/fe_comp_consultar/success.xml +41 -0
- data/test/fixtures/wsfe/fe_comp_tot_x_request/success.xml +9 -0
- data/test/fixtures/wsfe/fe_comp_ultimo_autorizado/success.xml +11 -0
- data/test/fixtures/wsfe/fe_dummy/success.xml +11 -0
- data/test/fixtures/wsfe/fe_param_get_cotizacion/dolar.xml +13 -0
- data/test/fixtures/wsfe/fe_param_get_cotizacion/inexistente.xml +14 -0
- data/test/fixtures/wsfe/fe_param_get_ptos_venta/success.xml +22 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_cbte/failure_1_error.xml +14 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_cbte/failure_2_errors.xml +18 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_cbte/success.xml +22 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_concepto/success.xml +17 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_doc/success.xml +16 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_iva/success.xml +16 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_monedas/success.xml +22 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_opcional/success.xml +16 -0
- data/test/fixtures/wsfe/fe_param_get_tipos_tributos/success.xml +16 -0
- data/test/fixtures/wsfe/fecae_solicitar/autorizacion_1_cbte.xml +30 -0
- data/test/fixtures/wsfe/fecae_solicitar/autorizacion_2_cbtes.xml +41 -0
- data/test/fixtures/wsfe/fecae_solicitar/dos_observaciones.xml +40 -0
- data/test/fixtures/wsfe/fecae_solicitar/una_observacion.xml +36 -0
- data/test/fixtures/wsfe/fecaea_consultar/success.xml +17 -0
- data/test/fixtures/wsfe/fecaea_reg_informativo/informe_rtdo_parcial.xml +45 -0
- data/test/fixtures/wsfe/fecaea_sin_movimiento_informar/success.xml +12 -0
- data/test/fixtures/wsfe/fecaea_solicitar/caea_ya_otorgado.xml +18 -0
- data/test/fixtures/wsfe/fecaea_solicitar/error_distinto.xml +18 -0
- data/test/fixtures/wsfe/fecaea_solicitar/success.xml +17 -0
- data/test/fixtures/wsfe/wsfe.wsdl +1372 -0
- data/test/fixtures/wsfecred/aceptar_f_e_cred/success.xml +14 -0
- data/test/fixtures/wsfecred/consultar_comprobantes/success.xml +17 -0
- data/test/fixtures/wsfecred/consultar_cta_cte/success.xml +13 -0
- data/test/fixtures/wsfecred/consultar_ctas_ctes/success.xml +16 -0
- data/test/fixtures/wsfecred/consultar_tipos_formas_cancelacion/success.xml +14 -0
- data/test/fixtures/wsfecred/consultar_tipos_motivos_rechazo/success.xml +14 -0
- data/test/fixtures/wsfecred/consultar_tipos_retenciones/failure.xml +14 -0
- data/test/fixtures/wsfecred/consultar_tipos_retenciones/success.xml +14 -0
- data/test/fixtures/wsfecred/dummy/success.xml +11 -0
- data/test/fixtures/wsfecred/wsfecred.wsdl +147 -0
- data/test/fixtures/wsrgiva/consultar_constancia_por_lote/one_error.xml +14 -0
- data/test/fixtures/wsrgiva/consultar_constancia_por_lote/success.xml +26 -0
- data/test/fixtures/wsrgiva/dummy/success.xml +11 -0
- data/test/fixtures/wsrgiva/wsrgiva.wsdl +118 -0
- data/test/support/savon_extensions.rb +43 -0
- data/test/test_helper.rb +44 -0
- metadata +319 -0
data/lib/arca/wsfe.rb
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arca
|
|
4
|
+
using Arca::CoreExt::Hash
|
|
5
|
+
|
|
6
|
+
class WSFE
|
|
7
|
+
WSDL = {
|
|
8
|
+
development: "https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL",
|
|
9
|
+
production: "https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL",
|
|
10
|
+
test: "#{Root}/test/fixtures/wsfe/wsfe.wsdl"
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
include TypeConversions
|
|
14
|
+
|
|
15
|
+
attr_reader :wsaa, :cuit
|
|
16
|
+
|
|
17
|
+
def initialize(options = {})
|
|
18
|
+
@cuit = options[:cuit]
|
|
19
|
+
@wsaa = WSAA.new options.merge(service: "wsfe")
|
|
20
|
+
@client = Client.new Hash(options[:savon]).reverse_merge(wsdl: WSDL[@wsaa.env],
|
|
21
|
+
convert_request_keys_to: :camelcase)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def dummy
|
|
25
|
+
request :fe_dummy
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def tipos_comprobantes
|
|
29
|
+
r = request :fe_param_get_tipos_cbte, auth
|
|
30
|
+
x2r get_array(r, :cbte_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def tipos_opcional
|
|
34
|
+
r = request :fe_param_get_tipos_opcional, auth
|
|
35
|
+
x2r get_array(r, :tipos_opcional), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def tipos_documentos
|
|
39
|
+
r = request :fe_param_get_tipos_doc, auth
|
|
40
|
+
x2r get_array(r, :doc_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def tipos_concepto
|
|
44
|
+
r = request :fe_param_get_tipos_concepto, auth
|
|
45
|
+
x2r get_array(r, :concepto_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def tipos_monedas
|
|
49
|
+
r = request :fe_param_get_tipos_monedas, auth
|
|
50
|
+
x2r get_array(r, :moneda), fch_desde: :date, fch_hasta: :date
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def tipos_iva
|
|
54
|
+
r = request :fe_param_get_tipos_iva, auth
|
|
55
|
+
x2r get_array(r, :iva_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def tipos_tributos
|
|
59
|
+
r = request :fe_param_get_tipos_tributos, auth
|
|
60
|
+
x2r get_array(r, :tributo_tipo), id: :integer, fch_desde: :date, fch_hasta: :date
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def tipos_condicion_iva_receptor
|
|
64
|
+
r = request :fe_param_get_condicion_iva_receptor, auth
|
|
65
|
+
x2r get_array(r, :condicion_iva_receptor), id: :integer
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def puntos_venta
|
|
69
|
+
r = request :fe_param_get_ptos_venta, auth
|
|
70
|
+
# Extract standard fields: nro, fch_baja, bloqueado
|
|
71
|
+
# Also extract emision_tipo (EmisionTipo), pve_nombre_fantasia (pveNombreFantasia),
|
|
72
|
+
# and pve_dominio (pveDominio) if present in response
|
|
73
|
+
# Note: WSDL only shows Nro, EmisionTipo, Bloqueado, FchBaja, but actual response
|
|
74
|
+
# may include additional fields like pveNombreFantasia and pveDominio
|
|
75
|
+
x2r get_array(r, :pto_venta),
|
|
76
|
+
nro: :integer,
|
|
77
|
+
fch_baja: :date,
|
|
78
|
+
bloqueado: :boolean,
|
|
79
|
+
emision_tipo: nil, # String field, no conversion needed
|
|
80
|
+
pve_nombre_fantasia: nil, # String field, may not be in WSDL but could be in response
|
|
81
|
+
pve_dominio: nil # String field, may not be in WSDL but could be in response
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def cotizacion(moneda_id)
|
|
85
|
+
request(:fe_param_get_cotizacion, auth.merge(mon_id: moneda_id))[:result_get][:mon_cotiz].to_f
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def autorizar_comprobantes(opciones)
|
|
89
|
+
comprobantes = opciones[:comprobantes]
|
|
90
|
+
mensaje = {
|
|
91
|
+
"FeCAEReq" => {
|
|
92
|
+
"FeCabReq" => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
|
|
93
|
+
"FeDetReq" => {
|
|
94
|
+
"FECAEDetRequest" => comprobantes.map { |comprobante| comprobante_to_request(comprobante, opciones) }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
mensaje = r2x(mensaje, cbte_fch: :date, fch_serv_desde: :date, fch_serv_hasta: :date, fch_vto_pago: :date)
|
|
99
|
+
r = request :fecae_solicitar, auth.merge(mensaje)
|
|
100
|
+
r = Array.wrap(r[:fe_det_resp][:fecae_det_response]).map do |h|
|
|
101
|
+
obs = Array.wrap(h[:observaciones] ? h[:observaciones][:obs] : nil)
|
|
102
|
+
h.select_keys(:cae, :cae_fch_vto, :resultado).merge(cbte_nro: h[:cbte_desde], observaciones: obs)
|
|
103
|
+
end
|
|
104
|
+
x2r r, cae_fch_vto: :date, fch_serv_desde: :date, fch_serv_hasta: :date, fch_vto_pago: :date, cbte_nro: :integer,
|
|
105
|
+
code: :integer
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def comprobante_to_request(comprobante, opciones)
|
|
109
|
+
nro = comprobante.delete :cbte_nro
|
|
110
|
+
iva = comprobante.delete :imp_iva
|
|
111
|
+
iva_receptor_id = comprobante.delete :condicion_iva_receptor_id
|
|
112
|
+
comprobante.delete :tributos if comprobante[:imp_trib] == 0
|
|
113
|
+
comprobante.merge! cbte_desde: nro, cbte_hasta: nro, "ImpIVA" => iva, "CondicionIVAReceptorId" => iva_receptor_id
|
|
114
|
+
comprobante.merge! periodo_asoc: opciones[:periodo_asoc] if opciones[:periodo_asoc]
|
|
115
|
+
comprobante
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def solicitar_caea
|
|
119
|
+
convertir_rta_caea request(:fecaea_solicitar, auth.merge(periodo_para_solicitud_caea))
|
|
120
|
+
rescue Arca::ResponseError => e
|
|
121
|
+
if e.code? 15_008
|
|
122
|
+
consultar_caea fecha_inicio_quincena_siguiente
|
|
123
|
+
else
|
|
124
|
+
raise
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def consultar_caea(fecha)
|
|
129
|
+
convertir_rta_caea request(:fecaea_consultar, auth.merge(periodo_para_consulta_caea(fecha)))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def periodo_para_solicitud_caea
|
|
133
|
+
periodo_para_consulta_caea fecha_inicio_quincena_siguiente
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def periodo_para_consulta_caea(fecha)
|
|
137
|
+
orden = fecha.day <= 15 ? 1 : 2
|
|
138
|
+
{ orden: orden, periodo: fecha.strftime("%Y%m") }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def fecha_inicio_quincena_siguiente
|
|
142
|
+
hoy = Date.today
|
|
143
|
+
hoy.day <= 15 ? hoy.change(day: 16) : hoy.next_month.change(day: 1)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def informar_comprobantes_caea(opciones)
|
|
147
|
+
comprobantes = opciones[:comprobantes]
|
|
148
|
+
mensaje = {
|
|
149
|
+
"FeCAEARegInfReq" => {
|
|
150
|
+
"FeCabReq" => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
|
|
151
|
+
"FeDetReq" => {
|
|
152
|
+
"FECAEADetRequest" => comprobantes.map do |comprobante|
|
|
153
|
+
comprobante_to_request(comprobante.merge("CAEA" => comprobante.delete(:caea)), opciones)
|
|
154
|
+
end
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
r = request :fecaea_reg_informativo, auth.merge(r2x(mensaje, cbte_fch: :date))
|
|
159
|
+
r = Array.wrap(r[:fe_det_resp][:fecaea_det_response]).map do |h|
|
|
160
|
+
obs = Array.wrap(h[:observaciones] ? h[:observaciones][:obs] : nil)
|
|
161
|
+
h.select_keys(:caea, :resultado).merge(cbte_nro: h[:cbte_desde], observaciones: obs)
|
|
162
|
+
end
|
|
163
|
+
x2r r, cbte_nro: :integer, code: :integer
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def informar_caea_sin_movimientos(caea, pto_vta)
|
|
167
|
+
request :fecaea_sin_movimiento_informar, auth.merge("CAEA" => caea, "PtoVta" => pto_vta)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def ultimo_comprobante_autorizado(opciones)
|
|
171
|
+
request(:fe_comp_ultimo_autorizado, auth.merge(opciones))[:cbte_nro].to_i
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def consultar_comprobante(opciones)
|
|
175
|
+
request(:fe_comp_consultar, auth.merge(fe_comp_cons_req: opciones))[:result_get]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def cant_max_registros_x_lote
|
|
179
|
+
request(:fe_comp_tot_x_request, auth)[:reg_x_req].to_i
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def auth
|
|
183
|
+
{ auth: wsaa.auth.merge(cuit: cuit) }
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
def request(action, body = nil)
|
|
189
|
+
response = @client.request(action, body).to_hash[:"#{action}_response"][:"#{action}_result"]
|
|
190
|
+
if response[:errors]
|
|
191
|
+
raise ResponseError, Array.wrap(response[:errors][:err])
|
|
192
|
+
else
|
|
193
|
+
response
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def get_array(response, array_element)
|
|
198
|
+
Array.wrap response[:result_get][array_element]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def convertir_rta_caea(r)
|
|
202
|
+
x2r r[:result_get], fch_tope_inf: :date, fch_vig_desde: :date, fch_vig_hasta: :date
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# WSFeCred: Web Service Factura Electrónica de Crédito MiPyMEs (ARCA).
|
|
4
|
+
# Gestión de cuentas corrientes originadas por Facturas Electrónicas de Crédito (FECRED).
|
|
5
|
+
# Documentación: Manual para el Desarrollador FECredService v2.0.3.
|
|
6
|
+
#
|
|
7
|
+
# Security: Token/sign from WSAA are never logged; TLS is handled by Client (SSL ciphers).
|
|
8
|
+
# Errors: Business/format errors raise ResponseError with :code and :msg; transport raise ServerError/NetworkError.
|
|
9
|
+
module Arca
|
|
10
|
+
class WSFeCred
|
|
11
|
+
WSDL = {
|
|
12
|
+
development: "https://fwshomo.afip.gov.ar/wsfecred/FECredService?wsdl",
|
|
13
|
+
production: "https://serviciosjava.afip.gob.ar/wsfecred/FECredService?wsdl",
|
|
14
|
+
test: "#{Root}/test/fixtures/wsfecred/wsfecred.wsdl"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
attr_reader :wsaa, :cuit
|
|
18
|
+
|
|
19
|
+
def initialize(options = {})
|
|
20
|
+
@cuit = normalize_cuit(options[:cuit])
|
|
21
|
+
@wsaa = WSAA.new options.merge(service: "wsfecred")
|
|
22
|
+
@client = Client.new Hash(options[:savon]).reverse_merge(
|
|
23
|
+
wsdl: WSDL[@wsaa.env],
|
|
24
|
+
soap_version: 1,
|
|
25
|
+
convert_request_keys_to: :camelcase
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def dummy
|
|
30
|
+
r = raw_request(:dummy, nil)
|
|
31
|
+
ret = r[:return] || r
|
|
32
|
+
{
|
|
33
|
+
app_server: ret[:appserver] || ret[:app_server],
|
|
34
|
+
auth_server: ret[:authserver] || ret[:auth_server],
|
|
35
|
+
db_server: ret[:dbserver] || ret[:db_server]
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# --- Operaciones de negocio ---
|
|
40
|
+
|
|
41
|
+
# Aceptar o cancelar total/parcialmente la Factura Electrónica de Crédito.
|
|
42
|
+
# id_cta_cte: { cod_cta_cte: long } o { id_factura: { cuit_emisor, cod_tipo_cmp, pto_vta, nro_cmp } }
|
|
43
|
+
# Opciones: array_confirmar_notas_dc, array_formas_cancelacion, array_retenciones,
|
|
44
|
+
# array_ajustes_operacion, tipo_cancelacion, importe_cancelado, importe_total_ret_pesos,
|
|
45
|
+
# importe_embargo_pesos, saldo_aceptado, cod_moneda, cotizacion_moneda_ult,
|
|
46
|
+
# informa_cbu, cbu_comprador
|
|
47
|
+
def aceptar_f_e_cred id_cta_cte, **opciones
|
|
48
|
+
body = { auth_request: auth, id_cta_cte: build_id_cta_cte(id_cta_cte) }
|
|
49
|
+
body.merge!(opciones_to_aceptar(opciones))
|
|
50
|
+
parse_operacion_response raw_request(:aceptar_f_e_cred, body), :aceptar_f_e_cred
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Rechazar la Cta.Cte. de una FECRED. array_motivos_rechazo: [ { cod_motivo, desc_motivo, justificacion } ]
|
|
54
|
+
def rechazar_f_e_cred(id_cta_cte, array_motivos_rechazo:)
|
|
55
|
+
motivos = Array(array_motivos_rechazo)
|
|
56
|
+
raise ArgumentError, "array_motivos_rechazo must have at least one motive" if motivos.empty?
|
|
57
|
+
|
|
58
|
+
body = {
|
|
59
|
+
auth_request: auth,
|
|
60
|
+
id_cta_cte: build_id_cta_cte(id_cta_cte),
|
|
61
|
+
array_motivos_rechazo: { motivo_rechazo: motivos }
|
|
62
|
+
}
|
|
63
|
+
parse_operacion_response raw_request(:rechazar_f_e_cred, body), :rechazar_f_e_cred
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Rechazar una Nota de Débito/Crédito individualmente.
|
|
67
|
+
def rechazar_nota_dc(id_comprobante, array_motivos_rechazo:)
|
|
68
|
+
motivos = Array(array_motivos_rechazo)
|
|
69
|
+
raise ArgumentError, "array_motivos_rechazo must have at least one motive" if motivos.empty?
|
|
70
|
+
|
|
71
|
+
body = {
|
|
72
|
+
auth_request: auth,
|
|
73
|
+
id_comprobante: build_id_comprobante(id_comprobante),
|
|
74
|
+
array_motivos_rechazo: { motivo_rechazo: motivos }
|
|
75
|
+
}
|
|
76
|
+
r = raw_request(:rechazar_nota_dc, body)
|
|
77
|
+
ret = get_return_value(r, :rechazar_nota_dc)
|
|
78
|
+
parse_response_errores! ret
|
|
79
|
+
ret
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Informar Factura al Agente de Depósito Colectivo. cta_agente: { cuit_agente, id_cuenta }
|
|
83
|
+
def informar_factura_agt_dpto_cltv(id_cta_cte, cta_agente:)
|
|
84
|
+
body = {
|
|
85
|
+
auth_request: auth,
|
|
86
|
+
id_cta_cte: build_id_cta_cte(id_cta_cte),
|
|
87
|
+
cta_agente: cta_agente
|
|
88
|
+
}
|
|
89
|
+
parse_operacion_response raw_request(:informar_factura_agt_dpto_cltv, body), :informar_factura_agt_dpto_cltv
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Informar cancelación total de la FECRED. array_formas_cancelacion: [ { codigo } ], importe_cancelacion
|
|
93
|
+
def informar_cancelacion_total_f_e_cred(id_cta_cte, array_formas_cancelacion:, importe_cancelacion:)
|
|
94
|
+
formas = Array(array_formas_cancelacion)
|
|
95
|
+
raise ArgumentError, "array_formas_cancelacion must have at least one item" if formas.empty?
|
|
96
|
+
|
|
97
|
+
body = {
|
|
98
|
+
auth_request: auth,
|
|
99
|
+
id_cta_cte: build_id_cta_cte(id_cta_cte),
|
|
100
|
+
array_formas_cancelacion: { codigo_descripcion: formas },
|
|
101
|
+
importe_cancelacion: importe_cancelacion
|
|
102
|
+
}
|
|
103
|
+
parse_operacion_response raw_request(:informar_cancelacion_total_f_e_cred, body),
|
|
104
|
+
:informar_cancelacion_total_f_e_cred
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Modificar opción de transferencia (ADC o SCA). opcion_transferencia: 'ADC' | 'SCA'
|
|
108
|
+
def modificar_opcion_transferencia(id_cta_cte, opcion_transferencia:)
|
|
109
|
+
body = {
|
|
110
|
+
auth_request: auth,
|
|
111
|
+
id_cta_cte: build_id_cta_cte(id_cta_cte),
|
|
112
|
+
opcion_transferencia: opcion_transferencia
|
|
113
|
+
}
|
|
114
|
+
parse_operacion_response raw_request(:modificar_opcion_transferencia, body), :modificar_opcion_transferencia
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Consultar comprobantes. rol_cuit_representada: 'Emisor'|'Receptor'. Filtros opcionales.
|
|
118
|
+
def consultar_comprobantes(rol_cuit_representada:, cuit_contraparte: nil, cod_tipo_cmp: nil,
|
|
119
|
+
estado_cmp: nil, fecha: nil, cod_cta_cte: nil, estado_cta_cte: nil, nro_pagina: nil)
|
|
120
|
+
body = { auth_request: auth, rol_cuit_representada: rol_cuit_representada }
|
|
121
|
+
body[:cuit_contraparte] = cuit_contraparte if cuit_contraparte
|
|
122
|
+
body[:cod_tipo_cmp] = cod_tipo_cmp if cod_tipo_cmp
|
|
123
|
+
body[:estado_cmp] = estado_cmp if estado_cmp
|
|
124
|
+
body[:fecha] = fecha if fecha
|
|
125
|
+
body[:cod_cta_cte] = cod_cta_cte if cod_cta_cte
|
|
126
|
+
body[:estado_cta_cte] = estado_cta_cte if estado_cta_cte
|
|
127
|
+
body[:nro_pagina] = nro_pagina if nro_pagina
|
|
128
|
+
r = raw_request(:consultar_comprobantes, body)
|
|
129
|
+
ret = get_return_value(r, :consultar_comprobantes)
|
|
130
|
+
parse_response_errores! ret
|
|
131
|
+
{
|
|
132
|
+
array_comprobantes: wrap_array(ret[:array_comprobantes]&.[](:comprobante)),
|
|
133
|
+
nro_pagina: ret[:nro_pagina],
|
|
134
|
+
hay_mas: ret[:hay_mas],
|
|
135
|
+
evento: ret[:evento],
|
|
136
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones])
|
|
137
|
+
}
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Consultar cuentas corrientes. rol_cuit_representada, filtros opcionales.
|
|
141
|
+
def consultar_ctas_ctes(rol_cuit_representada:, cuit_contraparte: nil, fecha: nil,
|
|
142
|
+
estado_cta_cte: nil, nro_pagina: nil, opcion_transferencia: nil)
|
|
143
|
+
body = { auth_request: auth, rol_cuit_representada: rol_cuit_representada }
|
|
144
|
+
body[:cuit_contraparte] = cuit_contraparte if cuit_contraparte
|
|
145
|
+
body[:fecha] = fecha if fecha
|
|
146
|
+
body[:estado_cta_cte] = estado_cta_cte if estado_cta_cte
|
|
147
|
+
body[:nro_pagina] = nro_pagina if nro_pagina
|
|
148
|
+
body[:opcion_transferencia] = opcion_transferencia if opcion_transferencia
|
|
149
|
+
r = raw_request(:consultar_ctas_ctes, body)
|
|
150
|
+
ret = get_return_value(r, :consultar_ctas_ctes)
|
|
151
|
+
parse_response_errores! ret
|
|
152
|
+
{
|
|
153
|
+
array_infos_cta_cte: wrap_array(ret[:array_infos_cta_cte]&.[](:info_cta_cte)),
|
|
154
|
+
nro_pagina: ret[:nro_pagina],
|
|
155
|
+
hay_mas: ret[:hay_mas],
|
|
156
|
+
evento: ret[:evento],
|
|
157
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones])
|
|
158
|
+
}
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Consultar detalle de una cuenta corriente.
|
|
162
|
+
def consultar_cta_cte(id_cta_cte)
|
|
163
|
+
body = { auth_request: auth, id_cta_cte: build_id_cta_cte(id_cta_cte) }
|
|
164
|
+
r = raw_request(:consultar_cta_cte, body)
|
|
165
|
+
ret = get_return_value(r, :consultar_cta_cte)
|
|
166
|
+
parse_response_errores! ret
|
|
167
|
+
ret.merge(cta_cte: ret[:cta_cte], array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones]))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Consultar cuentas del vendedor en Agentes de Depósito Colectivo.
|
|
171
|
+
def consultar_cuentas_en_agt_dpto_cltv
|
|
172
|
+
body = { auth_request: auth }
|
|
173
|
+
r = raw_request(:consultar_cuentas_en_agt_dpto_cltv, body)
|
|
174
|
+
ret = get_return_value(r, :consultar_cuentas_en_agt_dpto_cltv)
|
|
175
|
+
parse_response_errores! ret
|
|
176
|
+
{
|
|
177
|
+
array_cuentas_en_agente: wrap_array(ret[:array_cuentas_en_agente]&.[](:cuenta_en_agente)),
|
|
178
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones])
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Consultar monto obligado recepción para una CUIT y fecha de emisión.
|
|
183
|
+
def consultar_monto_obligado_recepcion(cuit_consultada:, fecha_emision:)
|
|
184
|
+
body = {
|
|
185
|
+
auth_request: auth,
|
|
186
|
+
cuit_consultada: normalize_cuit(cuit_consultada),
|
|
187
|
+
fecha_emision: format_date(fecha_emision)
|
|
188
|
+
}
|
|
189
|
+
r = raw_request(:consultar_monto_obligado_recepcion, body)
|
|
190
|
+
ret = get_return_value(r, :consultar_monto_obligado_recepcion)
|
|
191
|
+
parse_response_errores! ret
|
|
192
|
+
{
|
|
193
|
+
respuesta: ret[:respuesta],
|
|
194
|
+
monto_desde: ret[:monto_desde],
|
|
195
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones])
|
|
196
|
+
}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Tipos de retenciones habilitados.
|
|
200
|
+
def consultar_tipos_retenciones
|
|
201
|
+
body = { auth_request: auth }
|
|
202
|
+
r = raw_request(:consultar_tipos_retenciones, body)
|
|
203
|
+
ret = get_return_value(r, :consultar_tipos_retenciones)
|
|
204
|
+
parse_response_errores! ret
|
|
205
|
+
wrap_array(ret[:array_tipos_retenciones]&.[](:tipo_retencion))
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Tipos de motivos de rechazo.
|
|
209
|
+
def consultar_tipos_motivos_rechazo
|
|
210
|
+
body = { auth_request: auth }
|
|
211
|
+
r = raw_request(:consultar_tipos_motivos_rechazo, body)
|
|
212
|
+
ret = get_return_value(r, :consultar_tipos_motivos_rechazo)
|
|
213
|
+
parse_response_errores! ret
|
|
214
|
+
wrap_codigo_descripcion(ret[:array_codigo_descripcion])
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Facturas informadas al Agente de Depósito Colectivo.
|
|
218
|
+
def consultar_facturas_agt_dpto_cltv(id_cta_cte: nil, filtro_fecha: nil)
|
|
219
|
+
body = { auth_request: auth }
|
|
220
|
+
body[:id_cta_cte] = build_id_cta_cte(id_cta_cte) if id_cta_cte
|
|
221
|
+
body[:filtro_fecha] = filtro_fecha if filtro_fecha
|
|
222
|
+
r = raw_request(:consultar_facturas_agt_dpto_cltv, body)
|
|
223
|
+
ret = get_return_value(r, :consultar_facturas_agt_dpto_cltv)
|
|
224
|
+
parse_response_errores! ret
|
|
225
|
+
{
|
|
226
|
+
array_facturas_agt_dpto_cltv: wrap_array(ret[:array_facturas_agt_dpto_cltv]&.[](:factura_informada)),
|
|
227
|
+
evento: ret[:evento],
|
|
228
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones])
|
|
229
|
+
}
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Tipos de formas de cancelación.
|
|
233
|
+
def consultar_tipos_formas_cancelacion
|
|
234
|
+
body = { auth_request: auth }
|
|
235
|
+
r = raw_request(:consultar_tipos_formas_cancelacion, body)
|
|
236
|
+
ret = get_return_value(r, :consultar_tipos_formas_cancelacion)
|
|
237
|
+
parse_response_errores! ret
|
|
238
|
+
wrap_codigo_descripcion(ret[:array_codigo_descripcion])
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Remitos asociados a un comprobante.
|
|
242
|
+
def obtener_remitos(id_comprobante)
|
|
243
|
+
body = { auth_request: auth, id_comprobante: build_id_comprobante(id_comprobante) }
|
|
244
|
+
r = raw_request(:obtener_remitos, body)
|
|
245
|
+
ret = get_return_value(r, :obtener_remitos)
|
|
246
|
+
parse_response_errores! ret
|
|
247
|
+
wrap_array(ret[:array_ids_remitos]&.[](:id_comprobante))
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Historial de estados de un comprobante.
|
|
251
|
+
def consultar_historial_estados_comprobante(id_comprobante)
|
|
252
|
+
body = { auth_request: auth, id_comprobante: build_id_comprobante(id_comprobante) }
|
|
253
|
+
r = raw_request(:consultar_historial_estados_comprobante, body)
|
|
254
|
+
ret = get_return_value(r, :consultar_historial_estados_comprobante)
|
|
255
|
+
parse_response_errores! ret
|
|
256
|
+
{
|
|
257
|
+
id_comprobante: ret[:id_comprobante],
|
|
258
|
+
array_historial_estados: wrap_array(ret[:array_historial_estados]&.[](:estado_historico))
|
|
259
|
+
}
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Historial de estados de una cuenta corriente.
|
|
263
|
+
def consultar_historial_estados_cta_cte(id_cta_cte)
|
|
264
|
+
body = { auth_request: auth, id_cta_cte: build_id_cta_cte(id_cta_cte) }
|
|
265
|
+
r = raw_request(:consultar_historial_estados_cta_cte, body)
|
|
266
|
+
ret = get_return_value(r, :consultar_historial_estados_cta_cte)
|
|
267
|
+
parse_response_errores! ret
|
|
268
|
+
{
|
|
269
|
+
id_cta_cte: ret[:id_cta_cte],
|
|
270
|
+
array_historial_estados: wrap_array(ret[:array_historial_estados]&.[](:estado_historico))
|
|
271
|
+
}
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Tipos de ajustes de operación.
|
|
275
|
+
def consultar_tipos_ajustes_operacion
|
|
276
|
+
body = { auth_request: auth }
|
|
277
|
+
r = raw_request(:consultar_tipos_ajustes_operacion, body)
|
|
278
|
+
ret = get_return_value(r, :consultar_tipos_ajustes_operacion)
|
|
279
|
+
parse_response_errores! ret
|
|
280
|
+
wrap_codigo_descripcion(ret[:array_codigo_descripcion])
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
private
|
|
284
|
+
|
|
285
|
+
def raw_request(action, body)
|
|
286
|
+
# Savon normalizes WSDL operation names to snake_case (e.g. consultarTiposRetenciones -> :consultar_tipos_retenciones).
|
|
287
|
+
# "aceptarFECred" becomes :aceptar_fe_cred (not :aceptar_f_e_cred).
|
|
288
|
+
savon_action = action == :aceptar_f_e_cred ? :aceptar_fe_cred : action
|
|
289
|
+
message = if body.nil?
|
|
290
|
+
nil
|
|
291
|
+
else
|
|
292
|
+
body.key?(:auth_request) ? body : { auth_request: auth }.merge(body)
|
|
293
|
+
end
|
|
294
|
+
resp = @client.request(savon_action, message)
|
|
295
|
+
body_hash = response_body(resp)
|
|
296
|
+
raise ServerError, "Unexpected response structure" if body_hash.nil? || !body_hash.is_a?(Hash)
|
|
297
|
+
|
|
298
|
+
body_hash
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def auth
|
|
302
|
+
@wsaa.auth.merge(cuit_representada: cuit)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Response envelope key may be "dummyResponse" or :dummy_response depending on Savon.
|
|
306
|
+
def response_body(resp)
|
|
307
|
+
h = resp.respond_to?(:to_hash) ? resp.to_hash : resp
|
|
308
|
+
key = h.keys.find { |k| k.to_s =~ /Response$/i }
|
|
309
|
+
key ? h[key] : h
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Return value may be under operacionFECredReturn, consultarCtasCtesReturn, etc.
|
|
313
|
+
def get_return_value(response_hash, _action)
|
|
314
|
+
if response_hash.nil?
|
|
315
|
+
response_hash
|
|
316
|
+
else
|
|
317
|
+
key = response_hash.keys.find { |k| k.to_s =~ /return$/i }
|
|
318
|
+
key ? (response_hash[key] || response_hash) : response_hash
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def build_id_cta_cte(id_cta_cte)
|
|
323
|
+
if id_cta_cte.is_a?(Hash) && (id_cta_cte.key?(:cod_cta_cte) || id_cta_cte.key?(:id_factura))
|
|
324
|
+
id_cta_cte
|
|
325
|
+
else
|
|
326
|
+
raise ArgumentError,
|
|
327
|
+
"id_cta_cte must be { cod_cta_cte: long } or { id_factura: { cuit_emisor, cod_tipo_cmp, pto_vta, nro_cmp } }"
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def build_id_comprobante(id_comprobante)
|
|
332
|
+
raise ArgumentError, "id_comprobante must be a Hash" unless id_comprobante.is_a?(Hash)
|
|
333
|
+
|
|
334
|
+
required = %i[cuit_emisor cod_tipo_cmp pto_vta nro_cmp]
|
|
335
|
+
missing = required.reject { |k| id_comprobante.key?(k) }
|
|
336
|
+
raise ArgumentError, "id_comprobante must include #{required.join(', ')}" if missing.any?
|
|
337
|
+
|
|
338
|
+
id_comprobante.slice(*required)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def opciones_to_aceptar(opciones)
|
|
342
|
+
out = {}
|
|
343
|
+
out[:array_confirmar_notas_d_c] =
|
|
344
|
+
{ confirmar_nota: opciones[:array_confirmar_notas_dc] } if opciones[:array_confirmar_notas_dc]
|
|
345
|
+
out[:array_formas_cancelacion] =
|
|
346
|
+
{ codigo_descripcion: opciones[:array_formas_cancelacion] } if opciones[:array_formas_cancelacion]
|
|
347
|
+
out[:array_retenciones] = { retencion: opciones[:array_retenciones] } if opciones[:array_retenciones]
|
|
348
|
+
out[:array_ajustes_operacion] =
|
|
349
|
+
{ ajuste: opciones[:array_ajustes_operacion] } if opciones[:array_ajustes_operacion]
|
|
350
|
+
out[:tipo_cancelacion] = opciones[:tipo_cancelacion] if opciones[:tipo_cancelacion]
|
|
351
|
+
out[:importe_cancelado] = opciones[:importe_cancelado] if opciones[:importe_cancelado]
|
|
352
|
+
out[:importe_total_ret_pesos] = opciones[:importe_total_ret_pesos] if opciones[:importe_total_ret_pesos]
|
|
353
|
+
out[:importe_embargo_pesos] = opciones[:importe_embargo_pesos] if opciones[:importe_embargo_pesos]
|
|
354
|
+
out[:saldo_aceptado] = opciones[:saldo_aceptado] if opciones.key?(:saldo_aceptado)
|
|
355
|
+
out[:cod_moneda] = opciones[:cod_moneda] if opciones[:cod_moneda]
|
|
356
|
+
out[:cotizacion_moneda_ult] = opciones[:cotizacion_moneda_ult] if opciones.key?(:cotizacion_moneda_ult)
|
|
357
|
+
out[:informa_cbu] = opciones[:informa_cbu] if opciones.key?(:informa_cbu)
|
|
358
|
+
out[:cbu_comprador] = opciones[:cbu_comprador] if opciones[:cbu_comprador]
|
|
359
|
+
out
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def normalize_cuit(value)
|
|
363
|
+
if value.nil? || value == ""
|
|
364
|
+
0
|
|
365
|
+
else
|
|
366
|
+
value.to_s.gsub(/\D/, "").to_i
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def format_date(value)
|
|
371
|
+
if value.nil?
|
|
372
|
+
value
|
|
373
|
+
else
|
|
374
|
+
value.is_a?(String) ? value : value.to_date.strftime("%Y-%m-%d")
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def parse_operacion_response(r, action)
|
|
379
|
+
return_key = :"#{action}_return"
|
|
380
|
+
key = r.key?(return_key) ? return_key : r.keys.find { |k| k.to_s.include?("return") }
|
|
381
|
+
ret = key ? r[key] : r
|
|
382
|
+
parse_response_errores! ret.is_a?(Hash) ? ret : { key => ret }
|
|
383
|
+
ret = r[key] || r
|
|
384
|
+
{
|
|
385
|
+
resultado: ret[:resultado],
|
|
386
|
+
id_cta_cte: ret[:id_cta_cte],
|
|
387
|
+
evento: ret[:evento],
|
|
388
|
+
array_observaciones: wrap_codigo_descripcion(ret[:array_observaciones]),
|
|
389
|
+
array_errores: wrap_codigo_descripcion(ret[:array_errores])
|
|
390
|
+
}
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def parse_response_errores!(h)
|
|
394
|
+
return if h.nil? || !h.is_a?(Hash)
|
|
395
|
+
|
|
396
|
+
errs = wrap_codigo_descripcion(h[:array_errores])
|
|
397
|
+
raise ResponseError, errs.map { |e| error_to_code_msg(e, :codigo, :descripcion) } if errs && errs.any?
|
|
398
|
+
|
|
399
|
+
format_errs = wrap_codigo_descripcion_string(h[:array_errores_formato])
|
|
400
|
+
if format_errs && format_errs.any?
|
|
401
|
+
raise ResponseError, format_errs.map { |e| error_to_code_msg(e, :codigo, :descripcion) }
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def error_to_code_msg(e, code_key, msg_key)
|
|
406
|
+
code = e[code_key] || e[:codigo_descripcion]
|
|
407
|
+
msg = e[msg_key] || e[:descripcion] || ""
|
|
408
|
+
{ code: code.to_s, msg: msg.to_s }
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def wrap_array(val)
|
|
412
|
+
if val.nil?
|
|
413
|
+
[]
|
|
414
|
+
else
|
|
415
|
+
val = val.values.first if val.is_a?(Hash) && val.size == 1
|
|
416
|
+
Array.wrap(val)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def wrap_codigo_descripcion(val)
|
|
421
|
+
if val.nil?
|
|
422
|
+
[]
|
|
423
|
+
else
|
|
424
|
+
arr = val.is_a?(Hash) ? (val[:codigo_descripcion] || val[:codigoDescripcion]) : val
|
|
425
|
+
Array.wrap(arr)
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def wrap_codigo_descripcion_string(val)
|
|
430
|
+
if val.nil?
|
|
431
|
+
[]
|
|
432
|
+
else
|
|
433
|
+
arr = val.is_a?(Hash) ? (val[:codigo_descripcion_string] || val[:codigoDescripcionString]) : val
|
|
434
|
+
Array.wrap(arr)
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|