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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.travis.yml +12 -0
- data/.yardopts +9 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +36 -0
- data/Guardfile +26 -0
- data/LICENSE.txt +22 -0
- data/MX-Banxico.gemspec +29 -0
- data/README.md +140 -0
- data/REFERENCIAS.md +6 -0
- data/Rakefile +26 -0
- data/lib/MX/Banxico.rb +12 -0
- data/lib/MX/Banxico/historico.rb +4 -0
- data/lib/MX/Banxico/historico/tipo_de_cambio.rb +296 -0
- data/lib/MX/Banxico/series.rb +346 -0
- data/lib/MX/Banxico/tipo_de_cambio.rb +159 -0
- data/lib/MX/Banxico/version.rb +14 -0
- data/lib/MX/Banxico/web_services.rb +4 -0
- data/lib/MX/Banxico/web_services/tipo_de_cambio.rb +83 -0
- data/lib/MX/Banxico/web_services/web_service.rb +99 -0
- data/spec/MX/Banxico/historico/tipo_de_cambio_spec.rb +525 -0
- data/spec/MX/Banxico/series_spec.rb +475 -0
- data/spec/MX/Banxico/tipo_de_cambio_spec.rb +688 -0
- data/spec/MX/Banxico/web_services/tipo_de_cambio_spec.rb +152 -0
- data/spec/MX/Banxico/web_services/web_service_spec.rb +108 -0
- data/spec/fixtures/MX/Banxico/historico/respuestas_correctas/tipo_de_cambio.xml +2228 -0
- data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/mal_formado.xml +1 -0
- data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/serie_sin_valores.xml +28 -0
- data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/sin_series.xml +26 -0
- data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +393 -0
- data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/serie_sin_valores.xml +28 -0
- data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/sin_serie.xml +26 -0
- data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/reservas_internacionales_banxico.xml +41 -0
- data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tasas_de_interes_banxico.xml +50 -0
- data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tipos_de_cambio_banxico.xml +56 -0
- data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/udis_banxico.xml +41 -0
- data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_fecha_tipo_de_cambio.xml +41 -0
- data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_nodo_obs.xml +40 -0
- data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_valor_tipo_de_cambio.xml +41 -0
- data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +41 -0
- data/spec/spec_helper.rb +31 -0
- metadata +152 -0
@@ -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
|