diff --git a/lib/remote_census_api.rb b/lib/remote_census_api.rb new file mode 100644 index 000000000..ae8b124e5 --- /dev/null +++ b/lib/remote_census_api.rb @@ -0,0 +1,152 @@ +include DocumentParser +class RemoteCensusApi + + def call(document_type, document_number) + response = nil + get_document_number_variants(document_type, document_number).each do |variant| + response = Response.new(get_response_body(document_type, variant)) + return response if response.valid? + end + response + end + + class Response + def initialize(body) + @body = body + end + + def extract_value(path_value) + path = parse_path(path_value) + return nil unless path.present? + @body.dig(*path) + end + + def valid? + path_value = Setting["remote_census.response.valid"] + extract_value(path_value).present? + end + + def date_of_birth + path_value = Setting["remote_census.response.date_of_birth"] + str = extract_value(path_value) + return nil unless str.present? + day, month, year = str.match(/(\d\d?)\D(\d\d?)\D(\d\d\d?\d?)/)[1..3] + return nil unless day.present? && month.present? && year.present? + Time.zone.local(year.to_i, month.to_i, day.to_i).to_date + end + + def postal_code + path_value = Setting["remote_census.response.postal_code"] + extract_value(path_value) + end + + def district_code + path_value = Setting["remote_census.response.district"] + extract_value(path_value) + end + + def gender + path_value = Setting["remote_census.response.gender"] + + case extract_value(path_value) + when "Varón" + "male" + when "Mujer" + "female" + end + end + + def name + path_value_name = Setting["remote_census.response.name"] + path_value_surname = Setting["remote_census.response.surname"] + + "#{extract_value(path_value_name)} #{extract_value(path_value_surname)}" + end + + def parse_path(path_value) + path_value.split(".").map{ |section| section.to_sym } if path_value.present? + end + end + + private + + def get_response_body(document_type, document_number) + if end_point_available? + client.call(Setting["remote_census.request.method_name"].to_sym, message: request(document_type, document_number)).body + else + stubbed_response(document_type, document_number) + end + end + + def client + @client = Savon.client(wsdl: Setting["remote_census.general.endpoint"]) + end + + def request(document_type, document_number) + structure = eval(Setting["remote_census.request.structure"]) + + fill_in(structure, Setting["remote_census.request.document_type"], document_type) + fill_in(structure, Setting["remote_census.request.document_number"], document_number) + + structure + end + + def fill_in(structure, path_value, value) + path = parse_path(path_value) + + update_value(structure, path, value) if path.present? + end + + def parse_path(path_value) + path_value.split(".").map{ |section| section.to_sym } if path_value.present? + end + + def update_value(structure, path, value) + *path, final_key = path + to_set = path.empty? ? structure : structure.dig(*path) + + return unless to_set + to_set[final_key] = value + end + + def end_point_available? + Rails.env.staging? || Rails.env.preproduction? || Rails.env.production? + end + + def stubbed_response(document_type, document_number) + if (document_number == "12345678Z" || document_number == "12345678Y") && document_type == "1" + stubbed_valid_response + else + stubbed_invalid_response + end + end + + def stubbed_valid_response + { + get_habita_datos_response: { + get_habita_datos_return: { + datos_habitante: { + item: { + fecha_nacimiento_string: "31-12-1980", + identificador_documento: "12345678Z", + descripcion_sexo: "Varón", + nombre: "José", + apellido1: "García" + } + }, + datos_vivienda: { + item: { + codigo_postal: "28013", + codigo_distrito: "01" + } + } + } + } + } + end + + def stubbed_invalid_response + {get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {}, datos_vivienda: {}}}} + end + +end diff --git a/spec/lib/census_caller_spec.rb b/spec/lib/census_caller_spec.rb index d8ed6784d..9d0646854 100644 --- a/spec/lib/census_caller_spec.rb +++ b/spec/lib/census_caller_spec.rb @@ -42,6 +42,35 @@ describe CensusCaller do expect(response).to eq(census_api_response) end + + it "returns data from Remote Census API if it's available and valid" do + Setting["feature.remote_census"] = true + access_user_data = "get_habita_datos_response.get_habita_datos_return.datos_habitante.item" + access_residence_data = "get_habita_datos_response.get_habita_datos_return.datos_vivienda.item" + Setting["remote_census.response.date_of_birth"] = "#{access_user_data}.fecha_nacimiento_string" + Setting["remote_census.response.postal_code"] = "#{access_residence_data}.codigo_postal" + Setting["remote_census.response.valid"] = access_user_data + + remote_census_api_response = RemoteCensusApi::Response.new(get_habita_datos_response: { + get_habita_datos_return: { + datos_habitante: { item: { fecha_nacimiento_string: "1-1-1980" } } + } + }) + + local_census_response = LocalCensus::Response.new(create(:local_census_record)) + + expect_any_instance_of(RemoteCensusApi).to receive(:call).and_return(remote_census_api_response) + allow_any_instance_of(LocalCensus).to receive(:call).and_return(local_census_response) + + allow(RemoteCensusApi).to receive(:call).with(1, "12345678A") + allow(LocalCensus).to receive(:call).with(1, "12345678A") + + response = api.call(1, "12345678A") + + expect(response).to eq(remote_census_api_response) + + Setting["feature.remote_census"] = nil + end end end diff --git a/spec/lib/remote_census_api_spec.rb b/spec/lib/remote_census_api_spec.rb new file mode 100644 index 000000000..c023ce1b0 --- /dev/null +++ b/spec/lib/remote_census_api_spec.rb @@ -0,0 +1,51 @@ +require "rails_helper" + +describe RemoteCensusApi do + let(:api) { described_class.new } + + describe "#call" do + let(:invalid_body) { {get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {}}}} } + let(:valid_body) do + { + get_habita_datos_response: { + get_habita_datos_return: { + datos_habitante: { + item: { + fecha_nacimiento_string: "1-1-1980" + } + } + } + } + } + end + + before do + access_user_data = "get_habita_datos_response.get_habita_datos_return.datos_habitante.item" + access_residence_data = "get_habita_datos_response.get_habita_datos_return.datos_vivienda.item" + Setting["remote_census.response.date_of_birth"] = "#{access_user_data}.fecha_nacimiento_string" + Setting["remote_census.response.postal_code"] = "#{access_residence_data}.codigo_postal" + Setting["remote_census.response.valid"] = access_user_data + end + + it "returns the response for the first valid variant" do + allow(api).to receive(:get_response_body).with(1, "00123456").and_return(invalid_body) + allow(api).to receive(:get_response_body).with(1, "123456").and_return(invalid_body) + allow(api).to receive(:get_response_body).with(1, "0123456").and_return(valid_body) + + response = api.call(1, "123456") + + expect(response).to be_valid + expect(response.date_of_birth).to eq(Date.new(1980, 1, 1)) + end + + it "returns the last failed response" do + allow(api).to receive(:get_response_body).with(1, "00123456").and_return(invalid_body) + allow(api).to receive(:get_response_body).with(1, "123456").and_return(invalid_body) + allow(api).to receive(:get_response_body).with(1, "0123456").and_return(invalid_body) + response = api.call(1, "123456") + + expect(response).not_to be_valid + end + end + +end