MX-Banxico 1.0.2

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +12 -0
  5. data/.yardopts +9 -0
  6. data/CHANGELOG.md +5 -0
  7. data/Gemfile +36 -0
  8. data/Guardfile +26 -0
  9. data/LICENSE.txt +22 -0
  10. data/MX-Banxico.gemspec +29 -0
  11. data/README.md +140 -0
  12. data/REFERENCIAS.md +6 -0
  13. data/Rakefile +26 -0
  14. data/lib/MX/Banxico.rb +12 -0
  15. data/lib/MX/Banxico/historico.rb +4 -0
  16. data/lib/MX/Banxico/historico/tipo_de_cambio.rb +296 -0
  17. data/lib/MX/Banxico/series.rb +346 -0
  18. data/lib/MX/Banxico/tipo_de_cambio.rb +159 -0
  19. data/lib/MX/Banxico/version.rb +14 -0
  20. data/lib/MX/Banxico/web_services.rb +4 -0
  21. data/lib/MX/Banxico/web_services/tipo_de_cambio.rb +83 -0
  22. data/lib/MX/Banxico/web_services/web_service.rb +99 -0
  23. data/spec/MX/Banxico/historico/tipo_de_cambio_spec.rb +525 -0
  24. data/spec/MX/Banxico/series_spec.rb +475 -0
  25. data/spec/MX/Banxico/tipo_de_cambio_spec.rb +688 -0
  26. data/spec/MX/Banxico/web_services/tipo_de_cambio_spec.rb +152 -0
  27. data/spec/MX/Banxico/web_services/web_service_spec.rb +108 -0
  28. data/spec/fixtures/MX/Banxico/historico/respuestas_correctas/tipo_de_cambio.xml +2228 -0
  29. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/mal_formado.xml +1 -0
  30. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/serie_sin_valores.xml +28 -0
  31. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/sin_series.xml +26 -0
  32. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +393 -0
  33. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/serie_sin_valores.xml +28 -0
  34. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/sin_serie.xml +26 -0
  35. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/reservas_internacionales_banxico.xml +41 -0
  36. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tasas_de_interes_banxico.xml +50 -0
  37. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tipos_de_cambio_banxico.xml +56 -0
  38. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/udis_banxico.xml +41 -0
  39. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_fecha_tipo_de_cambio.xml +41 -0
  40. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_nodo_obs.xml +40 -0
  41. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_valor_tipo_de_cambio.xml +41 -0
  42. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +41 -0
  43. data/spec/spec_helper.rb +31 -0
  44. metadata +152 -0
@@ -0,0 +1,14 @@
1
+ # Módulo para todo lo relacionado con México.
2
+ #
3
+ module MX
4
+
5
+ # Herramientas para trabajar con información del Banco de México (Banxico).
6
+ #
7
+ module Banxico
8
+
9
+ # Versión de la gema.
10
+ #
11
+ VERSION = "1.0.2"
12
+
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ # Módulo para los webservices soportados.
2
+ #
3
+ module MX::Banxico::WebServices
4
+ end
@@ -0,0 +1,83 @@
1
+ # Modelo para conectarse al servicio web de Banxico y obtener los tipos de cambio vigentes al día de hoy.
2
+ #
3
+ # Esta clase hereda de {MX::Banxico::WebServices::WebService} para especializarse en la recuperación de los tipos de cambio.
4
+ #
5
+ class MX::Banxico::WebServices::TipoDeCambio < MX::Banxico::WebServices::WebService
6
+
7
+
8
+ # Tipos de cambio soportados.
9
+ #
10
+ TIPOS_DE_CAMBIO = MX::Banxico::Series.tipos_de_cambio.keys.dup.freeze
11
+
12
+ # Inicialización del cliente de {http://savonrb.com/version2/testing.html Savon}.
13
+ #
14
+ self.init_client
15
+
16
+ # @!method operations
17
+ # Operaciones soportadas en este web service via {http://savonrb.com/version2/testing.html Savon}.
18
+ #
19
+ operations :tipos_de_cambio_banxico
20
+
21
+
22
+ # Obtiene el tipo de cambio del día.
23
+ #
24
+ # @param tipo [Symbol] el tipo de cambio deseado. Ver {TIPOS_DE_CAMBIO}.
25
+ # @param intentos [Ingeger] el número de intentos para obtener el tipo de cambio.
26
+ #
27
+ # @return [MX::Banxico::TipoDeCambio] si la petición es exitosa, la estructura con el tipo de cambio.
28
+ # @return [String] si la petición no es exitosa, una cadena con la descripción del error.
29
+ #
30
+ # @raise [ArgumentError] cuando el tipo dado no está soportado. Ver {TIPOS_DE_CAMBIO}.
31
+ #
32
+ def obtener(tipo, intentos = 5)
33
+ raise ArgumentError.new("El tipo de cambio no está soportado (#{tipo}).") unless TIPOS_DE_CAMBIO.member?(tipo.to_sym)
34
+ respuesta = realizar_operacion(:tipos_de_cambio_banxico, intentos)
35
+ if respuesta.errores?
36
+ return respuesta.errores
37
+ else
38
+ xml_doc_cuerpo_respuesta = Nokogiri::XML(respuesta.cuerpo, nil, CODIFICACION_WS )
39
+ nodo_valor = xml_doc_cuerpo_respuesta.root.at_xpath(xpath_tipo_de_cambio(tipo))
40
+ if nodo_valor
41
+ tdc_o_error = procesar_nodo_obs_tipo_de_cambio(nodo_valor, tipo)
42
+ return tdc_o_error
43
+ else
44
+ return "No fue posible extraer los valores del XML del nodo bm:Obs al consultar el servicio web." +
45
+ " Operación: #{:tipos_de_cambio_banxico}. XPath: #{xpath_tipo_de_cambio(tipo)}." +
46
+ "\n\n #{respuesta.cuerpo}"
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+
53
+ private
54
+
55
+ # Procesa el nodo del XML de la respuesta de la petición que contiene la información del tipo de cambio.
56
+ #
57
+ # @param nodo_valor [Nokogiri::XML::Node] nodo de la serie con el valor y fecha del tipo de cambio (bm:Obs).
58
+ # @param tipo [Symbol] el tipo de cambio solicitado. Ver {TIPOS_DE_CAMBIO}.
59
+ #
60
+ # @return [MX::Banxico::TipoDeCambio] si la obtención del valor y la fecha es exitosa, la estructura con el tipo de cambio.
61
+ # @return [String] si la obtención del valor y la fecha no es exitosa, una cadena con la descripción del error.
62
+ #
63
+ def procesar_nodo_obs_tipo_de_cambio(nodo_valor, tipo)
64
+ begin
65
+ return MX::Banxico::TipoDeCambio.new(tipo, nodo_valor[:TIME_PERIOD], nodo_valor[:OBS_VALUE])
66
+ rescue ArgumentError => e
67
+ return "Error al crear el tipo de cambio a partir del nodo bm:Obs. Error: #{e.message}"
68
+ end
69
+ end
70
+
71
+ # XPath con la ruta del nodo `bm:Obs` del identificador de la serie de acuerdo a su tipo.
72
+ #
73
+ # @param tipo [Symbol] el tipo de cambio solicitado. Ver {TIPOS_DE_CAMBIO}.
74
+ #
75
+ # @return [String] la ruta (XPath) del nodo de la serie de acuerdo al tipo dado.
76
+ #
77
+ def xpath_tipo_de_cambio(tipo)
78
+ id = MX::Banxico::Series.identificador(:tipos_de_cambio, tipo)
79
+ %Q{bm:DataSet/bm:Series[@IDSERIE="#{id}"]/bm:Obs}
80
+ end
81
+
82
+
83
+ end
@@ -0,0 +1,99 @@
1
+ #
2
+ # Modelo para conectarse al servicio web de Banxico por medio de Savon::Model.
3
+ #
4
+ #
5
+ # @note Savon crea métodos por omisión de acuerdo a las operaciones soportadas por el servicio web, tano a nivel
6
+ # de clase como de instancia.
7
+ #
8
+ class MX::Banxico::WebServices::WebService
9
+ extend Savon::Model
10
+
11
+
12
+ # Estructura para guardar el cuerpo de la respuesta de una operación o los errores
13
+ #
14
+ Respuesta = Struct.new(:cuerpo, :errores) do
15
+
16
+ # Determina si la operación fue exitosa.
17
+ #
18
+ # @return `true` si tuvo éxito, `false` de lo contrario.
19
+ #
20
+ def exito?
21
+ errores.nil?
22
+ end
23
+
24
+ # Determina si hubo errores en al efectuar la operación.
25
+ #
26
+ # @return `true` si hubieron errores, `false` de lo contrario.
27
+ #
28
+ def errores?
29
+ !exito?
30
+ end
31
+
32
+ end
33
+
34
+
35
+ # URL con la definición del servicio web.
36
+ #
37
+ WSDL = "http://www.banxico.org.mx/DgieWSWeb/DgieWS?WSDL"
38
+
39
+ # Codificación de la petición y respuesta del servicio
40
+ # ¡guácala, no es UTF-8 la codificación que manejan en Banxico!
41
+ #
42
+ CODIFICACION_WS = "ISO-8859-1"
43
+
44
+
45
+ # Operaciones soportadas por el servicio web de Banxico:
46
+ # * Reservas internacionales
47
+ # * Tasas de interés
48
+ # * Tipos de Cambio
49
+ # * UDIS
50
+ #
51
+ OPERACIONES_WS = [ :reservas_internacionales_banxico, :tasas_de_interes_banxico, :tipos_de_cambio_banxico, :udis_banxico ]
52
+
53
+ # @!method client
54
+ # Definición del cliente de Savon
55
+ #
56
+
57
+ # Inicializa el cliente de Savon.
58
+ #
59
+ def self.init_client
60
+ client wsdl: WSDL, encoding: CODIFICACION_WS, open_timeout: 5, read_timeout: 5
61
+ end
62
+
63
+ # Inicialización del cliente de Savon
64
+ #
65
+ self.init_client
66
+
67
+ # Realiza la operación solicitada en un máximo de intentos dados.
68
+ #
69
+ # @param op [Symbol] el nombre de la operación soportada a efectuarse. Ver {OPERACIONES_WS}.
70
+ # @param intentos [Fixnum] el número de intentos en los que se tratará de recuperar la respuesta de la operación.
71
+ #
72
+ # @return [Hash] con el cuerpo de la respuesta de la operación en la llave `:cuerpo` o una descripción de los errores
73
+ # ocurridos en la llave `:errores`.
74
+ #
75
+ def realizar_operacion(op, intentos = 5)
76
+ raise ArgumentError.new("La operación #{op} no está soportada.") unless OPERACIONES_WS.member?(op.to_sym)
77
+ raise ArgumentError.new("El número de intentos debe ser mayor o igual a 1.") if (!intentos.is_a?(Integer) or intentos < 1)
78
+ errores = ""
79
+ 1.upto(intentos) do |intento|
80
+ begin
81
+ resp = client.call(op.to_sym)
82
+ return Respuesta.new(resp.body[:"#{op}_response"][:result]) if resp.success?
83
+ rescue Exception => e
84
+ errores = "#{errores}Intento #{intento}: #{e.message}. "
85
+ end
86
+ errores = "#{errores}Número de intentos agotados #{intentos}." if intento == intentos
87
+ end
88
+ Respuesta.new(nil, errores)
89
+ end
90
+
91
+ # Arreglo con las operaciones soportadas por el servicio web.
92
+ #
93
+ # @return [Array] un arreglo con las operaciones soportados.
94
+ #
95
+ def self.operaciones
96
+ OPERACIONES_WS
97
+ end
98
+
99
+ end
@@ -0,0 +1,525 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ require 'webmock/rspec'
3
+
4
+ describe MX::Banxico::Historico::TipoDeCambio, :tipo_de_cambio_historico do
5
+ let!(:post_url){ "#{described_class::URL}#{described_class::POST_PATH}" }
6
+
7
+ before(:context) { WebMock.disable! }
8
+ after(:context) { WebMock.reset! }
9
+
10
+
11
+ describe '#de_serie' do
12
+
13
+ context 'cuando no existe la serie' do
14
+ let!(:serie){ :serie_inexistente }
15
+ let!(:historico_tdc){ described_class.new }
16
+ let!(:arr){ historico_tdc.de_serie(serie) }
17
+
18
+ it 'es nil' do
19
+ historico_tdc = described_class.new
20
+ expect(historico_tdc.de_serie(:serie_inexistente)).to be_nil
21
+ end
22
+
23
+
24
+ describe '#errores' do
25
+
26
+ it 'es la descripción del error' do
27
+ expect(historico_tdc.errores).to eq "Error: La serie no existe (serie: #{serie})."
28
+ end
29
+
30
+ end
31
+
32
+
33
+ describe '#errores?' do
34
+
35
+ it 'es true' do
36
+ expect(historico_tdc.errores?).to be_truthy
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+
44
+ context 'cuando la petición tuvo éxito' do
45
+
46
+ context 'cuando no es una respuesta satisfactoria' do
47
+ before(:context) { WebMock.enable! }
48
+ let!(:serie){ :dolar_fix }
49
+
50
+ [404, 500].each do |codigo|
51
+
52
+ context "cuando no se encontró la página (#{codigo})" do
53
+ let!(:req){ stub_request(:any, post_url).to_return(status: codigo) }
54
+ let(:historico_tdc){ described_class.new }
55
+ let!(:arr){ historico_tdc.de_serie(serie) }
56
+
57
+ it 'es nil' do
58
+ expect(arr).to be_nil
59
+ end
60
+
61
+
62
+ describe '#errores' do
63
+
64
+ it 'es la descripción del error' do
65
+ expect(historico_tdc.errores).to eq "Error: código de error #{codigo}."
66
+ end
67
+
68
+ end
69
+
70
+
71
+ describe '#errores?' do
72
+
73
+ it 'es true' do
74
+ expect(historico_tdc.errores?).to be_truthy
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+
86
+ context 'cuando se obtuvo una respuesta satisfactoria (200 - OK)' do
87
+ let!(:serie){ :dolar_fix }
88
+ let!(:año){ 2015 }
89
+
90
+ context 'cuando la respuesta tiene series' do
91
+ let(:historico_tdc){ described_class.new }
92
+
93
+
94
+ context 'cuando se realiza una conexión al servicio' do
95
+ before(:context) { WebMock.disable! }
96
+ let!(:arr){ historico_tdc.de_serie(serie, año, año) }
97
+
98
+ it 'es un arreglo de MX::Banxico::TipoDeCambio' do
99
+ expect(arr).to be_a Array
100
+ arr.each do |tdc|
101
+ expect(tdc).to be_a MX::Banxico::TipoDeCambio
102
+ expect(tdc.moneda).to eq serie
103
+ end
104
+ end
105
+
106
+ it 'el arreglo tiene un elemento por cada día el año' do
107
+ expect(arr.size).to eq dias_tipos_de_cambio_2015(serie)
108
+ end
109
+
110
+
111
+ describe '#errores' do
112
+
113
+ it 'es la descripción del error' do
114
+ expect(historico_tdc.errores).to be_nil
115
+ end
116
+
117
+ end
118
+
119
+
120
+ describe '#errores?' do
121
+
122
+ it 'es true' do
123
+ expect(historico_tdc.errores?).to be_falsey
124
+ end
125
+
126
+ end
127
+
128
+ end
129
+
130
+
131
+ context 'cuando se usa un stub de la conexión' do
132
+ before(:context) { WebMock.enable! }
133
+ let!(:cuerpo_ok){ File.read("spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/respuesta_correcta.xml") }
134
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_ok) }
135
+ let!(:arr){ historico_tdc.de_serie(serie, año, año) }
136
+
137
+ it 'es un arreglo de MX::Banxico::TipoDeCambio' do
138
+ expect(arr).to be_a Array
139
+ arr.each do |tdc|
140
+ expect(tdc).to be_a MX::Banxico::TipoDeCambio
141
+ expect(tdc.moneda).to eq serie
142
+ end
143
+ end
144
+
145
+ it 'el arreglo tiene un elemento por cada día el año' do
146
+ expect(arr.size).to eq dias_tipos_de_cambio_2015(serie)
147
+ end
148
+
149
+
150
+ describe '#errores' do
151
+
152
+ it 'es la descripción del error' do
153
+ expect(historico_tdc.errores).to be_nil
154
+ end
155
+
156
+ end
157
+
158
+
159
+ describe '#errores?' do
160
+
161
+ it 'es true' do
162
+ expect(historico_tdc.errores?).to be_falsey
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+
171
+
172
+ context 'cuando la respuesta no tiene serie' do
173
+ before(:context) { WebMock.enable! }
174
+ let!(:cuerpo_sin_series){ File.read("spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/sin_serie.xml") }
175
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_sin_series) }
176
+ let!(:historico_tdc){ described_class.new }
177
+ let!(:arr){ historico_tdc.de_serie(serie, año, año) }
178
+
179
+ it 'es nil' do
180
+ expect(arr).to be_nil
181
+ end
182
+
183
+
184
+ describe '#errores' do
185
+
186
+ it 'es la descripción del error' do
187
+ expect(historico_tdc.errores).to eq "Error: No se encontró información de la serie #{serie} dentro de la respuesta de la petición."
188
+ end
189
+
190
+ end
191
+
192
+
193
+ describe '#errores?' do
194
+
195
+ it 'es true' do
196
+ expect(historico_tdc.errores?).to be_truthy
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+
203
+
204
+ context 'cuando la respuesta tiene series sin tipos de cambio' do
205
+ before(:context) { WebMock.enable! }
206
+ let!(:cuerpo_sin_tdc){ File.read("spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/serie_sin_valores.xml") }
207
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_sin_tdc) }
208
+ let!(:historico_tdc){ described_class.new }
209
+ let!(:arr){ historico_tdc.de_serie(serie, año, año) }
210
+
211
+ it 'es nil' do
212
+ expect(arr).to be_nil
213
+ end
214
+
215
+
216
+ describe '#errores' do
217
+
218
+ it 'es la descripción del error' do
219
+ expect(historico_tdc.errores).to eq "Error: No se encontró información de la serie #{serie} dentro de la respuesta de la petición."
220
+ end
221
+
222
+ end
223
+
224
+
225
+ describe '#errores?' do
226
+
227
+ it 'es true' do
228
+ expect(historico_tdc.errores?).to be_truthy
229
+ end
230
+
231
+ end
232
+
233
+ end
234
+
235
+
236
+ context 'cuando la respuesta no tiene la estructura esperada' do
237
+ before(:context) { WebMock.enable! }
238
+ let!(:cuerpo){ File.read("spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/mal_formado.xml") }
239
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo) }
240
+ let!(:historico_tdc){ described_class.new }
241
+ let!(:arr){ historico_tdc.de_serie(:dolar_fix) }
242
+
243
+ it 'es nil' do
244
+ expect(arr).to be_nil
245
+ end
246
+
247
+
248
+ describe '#errores' do
249
+
250
+ it 'tiene el mensaje de error' do
251
+ expect(historico_tdc.errores).to eq "Error: La respuesta de la petición no tiene el formato correcto."
252
+ end
253
+
254
+ end
255
+
256
+
257
+ describe '#errores?' do
258
+
259
+ it 'es true' do
260
+ expect(historico_tdc.errores?).to be_truthy
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+
267
+ end
268
+
269
+ end
270
+
271
+ end
272
+
273
+
274
+ describe '#completo' do
275
+
276
+ context 'cuando la petición tuvo éxito' do
277
+
278
+ context 'cuando no es una respuesta satisfactoria' do
279
+ before(:context) { WebMock.enable! }
280
+
281
+ [404, 500].each do |codigo|
282
+
283
+ context "cuando no se encontró la página (#{codigo})" do
284
+ let!(:req){ stub_request(:any, post_url).to_return(status: codigo) }
285
+ let(:historico_tdc){ described_class.new }
286
+ let!(:arr){ historico_tdc.completo }
287
+
288
+ it 'es nil' do
289
+ expect(arr).to be_nil
290
+ end
291
+
292
+
293
+ describe '#errores' do
294
+
295
+ it 'es la descripción del error' do
296
+ expect(historico_tdc.errores).to eq "Error: código de error #{codigo}."
297
+ end
298
+
299
+ end
300
+
301
+
302
+ describe '#errores?' do
303
+
304
+ it 'es true' do
305
+ expect(historico_tdc.errores?).to be_truthy
306
+ end
307
+
308
+ end
309
+
310
+ end
311
+
312
+ end
313
+
314
+ end
315
+
316
+
317
+ context 'cuando se obtuvo una respuesta satisfactoria (200 - OK)' do
318
+ let!(:año){ 2015 }
319
+
320
+ context 'cuando la respuesta tiene series' do
321
+ let!(:nombres_series){ MX::Banxico::Series.nombres(:tipos_de_cambio) }
322
+ let(:historico_tdc){ described_class.new }
323
+
324
+
325
+ context 'cuando se realiza una conexión al servicio' do
326
+ before(:context) { WebMock.disable! }
327
+ let!(:arr){ historico_tdc.completo(año, año) }
328
+
329
+ it 'es un arreglo de MX::Banxico::TipoDeCambio' do
330
+ expect(arr).to be_a Array
331
+ nombres_series.each do |serie|
332
+ arr.select{|t| t.moneda == serie }.each do |tdc|
333
+ expect(tdc).to be_a MX::Banxico::TipoDeCambio
334
+ end
335
+ end
336
+ end
337
+
338
+ it 'el arreglo tiene un elemento por cada día el año' do
339
+ nombres_series.each do |serie|
340
+ expect(arr.select{|t| t.moneda == serie }.size).to eq dias_tipos_de_cambio_2015(serie)
341
+ end
342
+ end
343
+
344
+
345
+ describe '#errores' do
346
+
347
+ it 'es la descripción del error' do
348
+ expect(historico_tdc.errores).to be_nil
349
+ end
350
+
351
+ end
352
+
353
+
354
+ describe '#errores?' do
355
+
356
+ it 'es true' do
357
+ expect(historico_tdc.errores?).to be_falsey
358
+ end
359
+
360
+ end
361
+
362
+ end
363
+
364
+
365
+ context 'cuando se usa un stub de la conexión' do
366
+ before(:context) { WebMock.enable! }
367
+ let!(:cuerpo_ok){ File.read("spec/fixtures/MX/Banxico/historico/respuestas_correctas/tipo_de_cambio.xml") }
368
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_ok) }
369
+ let!(:arr){ historico_tdc.completo(año, año) }
370
+
371
+ it 'es un arreglo de MX::Banxico::TipoDeCambio' do
372
+ expect(arr).to be_a Array
373
+ nombres_series.each do |serie|
374
+ arr.select{|t| t.moneda == serie }.each do |tdc|
375
+ expect(tdc).to be_a MX::Banxico::TipoDeCambio
376
+ end
377
+ end
378
+ end
379
+
380
+ it 'el arreglo tiene un elemento por cada día el año' do
381
+ nombres_series.each do |serie|
382
+ expect(arr.select{|t| t.moneda == serie }.size).to eq dias_tipos_de_cambio_2015(serie)
383
+ end
384
+ end
385
+
386
+
387
+ describe '#errores' do
388
+
389
+ it 'es la descripción del error' do
390
+ expect(historico_tdc.errores).to be_nil
391
+ end
392
+
393
+ end
394
+
395
+
396
+ describe '#errores?' do
397
+
398
+ it 'es true' do
399
+ expect(historico_tdc.errores?).to be_falsey
400
+ end
401
+
402
+ end
403
+
404
+ end
405
+
406
+ end
407
+
408
+
409
+ context 'cuando la respuesta no tiene series' do
410
+ before(:context) { WebMock.enable! }
411
+ let!(:cuerpo_sin_series){ File.read("spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/sin_series.xml") }
412
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_sin_series) }
413
+ let!(:historico_tdc){ described_class.new }
414
+ let!(:arr){ historico_tdc.completo(año, año) }
415
+
416
+ it 'es nil' do
417
+ expect(arr).to be_nil
418
+ end
419
+
420
+
421
+ describe '#errores' do
422
+
423
+ it 'es la descripción del error' do
424
+ expect(historico_tdc.errores).to eq "Error: No se encontraron series en la respuesta."
425
+ end
426
+
427
+ end
428
+
429
+
430
+ describe '#errores?' do
431
+
432
+ it 'es true' do
433
+ expect(historico_tdc.errores?).to be_truthy
434
+ end
435
+
436
+ end
437
+
438
+ end
439
+
440
+
441
+ context 'cuando la respuesta tiene series sin tipos de cambio' do
442
+ before(:context) { WebMock.enable! }
443
+ let!(:cuerpo_sin_tdc){ File.read("spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/serie_sin_valores.xml") }
444
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo_sin_tdc) }
445
+ let!(:historico_tdc){ described_class.new }
446
+ let!(:arr){ historico_tdc.completo(año, año) }
447
+
448
+ it 'es nil' do
449
+ expect(arr).to be_nil
450
+ end
451
+
452
+
453
+ describe '#errores' do
454
+
455
+ it 'es la descripción del error' do
456
+ expect(historico_tdc.errores).to eq "Error: No se encontraron series en la respuesta."
457
+ end
458
+
459
+ end
460
+
461
+
462
+ describe '#errores?' do
463
+
464
+ it 'es true' do
465
+ expect(historico_tdc.errores?).to be_truthy
466
+ end
467
+
468
+ end
469
+
470
+ end
471
+
472
+
473
+ context 'cuando la respuesta no tiene la estructura esperada' do
474
+ before(:context) { WebMock.enable! }
475
+ let!(:cuerpo){ File.read("spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/mal_formado.xml") }
476
+ let!(:req){ stub_request(:any, post_url).to_return(status: 200, body: cuerpo) }
477
+ let!(:historico_tdc){ described_class.new }
478
+ let!(:arr){ historico_tdc.completo }
479
+
480
+ it 'es nil' do
481
+ expect(arr).to be_nil
482
+ end
483
+
484
+
485
+ describe '#errores' do
486
+
487
+ it 'tiene el mensaje de error' do
488
+ expect(historico_tdc.errores).to eq "Error: La respuesta de la petición no tiene el formato correcto."
489
+ end
490
+
491
+ end
492
+
493
+
494
+ describe '#errores?' do
495
+
496
+ it 'es true' do
497
+ expect(historico_tdc.errores?).to be_truthy
498
+ end
499
+
500
+ end
501
+
502
+ end
503
+
504
+ end
505
+
506
+ end
507
+
508
+ end
509
+
510
+
511
+
512
+ # Cuenta manual :'(
513
+ def dias_tipos_de_cambio_2015(serie)
514
+ case serie
515
+ when :dolar_canadiense
516
+ 241
517
+ when :dolar_liquidacion
518
+ 365
519
+ else
520
+ 251
521
+ end
522
+ end
523
+
524
+
525
+ end