diff --git a/lib/census_api.rb b/lib/census_api.rb index 7078fa828..0eb3ee35d 100644 --- a/lib/census_api.rb +++ b/lib/census_api.rb @@ -1,7 +1,54 @@ class CensusApi def call(document_type, document_number) - Response.new(get_response_body(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 + + def get_document_number_variants(document_type, document_number) + # Delete all non-alphanumerics + document_number = document_number.to_s.gsub(/[^0-9A-Za-z]/i, '') + variants = [] + + if is_dni?(document_type) + # If a letter exists at the end, delete it and put it on the letter var + letter = document_number.last + if letter[/[A-Za-z]/] == letter + document_number = document_number[0..-2] + else + letter = nil + end + + document_number = document_number.last(8) # Keep only the last 7 digits + document_number = document_number.gsub(/^0+/, '') # Removes leading zeros + + # if the number has less than 7 digits, pad with zeros to the left and add each variant to the list + # For example, if the initial document_number is 1234, possible numbers should have + # [1234, 01234, 001234, 0001234] + possible_numbers = [] + possible_numbers << document_number unless document_number.blank? + while document_number.size < 8 + document_number = "0#{document_number}" + possible_numbers << document_number + end + + variants += possible_numbers + + # if a letter was given, try the numbers followed by the letter in upper and lowercase + if letter.present? then + possible_numbers.each do |number| + variants << number + letter.downcase << number + letter.upcase + end + end + else # not a DNI + variants << document_number + end + + variants end class Response @@ -60,4 +107,8 @@ class CensusApi def stubbed_response_body {:get_habita_datos_response=>{:get_habita_datos_return=>{:hay_errores=>false, :datos_habitante=>{:item=>{:fecha_nacimiento_string=>"31-12-1980", :identificador_documento=>"12345678Z", }}, :datos_vivienda=>{:item=>{:codigo_postal=>"28013"}}}}} end + + def is_dni?(document_type) + document_type.to_s == "1" + end end diff --git a/spec/lib/census_api_spec.rb b/spec/lib/census_api_spec.rb new file mode 100644 index 000000000..a49133d23 --- /dev/null +++ b/spec/lib/census_api_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +describe CensusApi do + let(:api) { described_class.new } + + describe '#get_document_number_variants' do + it "trims and cleans up entry" do + expect(api.get_document_number_variants(2, ' 1 2@ 34')).to eq(['1234']) + end + + it "returns only one try for passports & residence cards" do + expect(api.get_document_number_variants(2, '1234')).to eq(['1234']) + expect(api.get_document_number_variants(3, '1234')).to eq(['1234']) + end + + it 'takes only the last 8 digits for dnis and resicence cards' do + expect(api.get_document_number_variants(1, '543212345678')).to eq(['12345678']) + end + + it 'tries all the dni variants padding with zeroes' do + expect(api.get_document_number_variants(1, '0123456')).to eq(['123456', '0123456', '00123456']) + expect(api.get_document_number_variants(1, '00123456')).to eq(['123456', '0123456', '00123456']) + end + + it 'adds upper and lowercase letter when the letter is present' do + expect(api.get_document_number_variants(1, '1234567A')).to eq(['1234567', '01234567', '1234567a', '1234567A', '01234567a', '01234567A']) + end + end + + describe '#call' do + let(:invalid_body) { {get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {}}}} } + let(:valid_body){ {get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {item: {fecha_nacimiento_string: "1/1/1980"}}}}} } + + 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) + expect(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('1/1/1980') + end + + it "returns the last failed response" do + expect(api).to receive(:get_response_body).with(1, "00123456").and_return(invalid_body) + expect(api).to receive(:get_response_body).with(1, "123456").and_return(invalid_body) + expect(api).to receive(:get_response_body).with(1, "0123456").and_return(invalid_body) + response = api.call(1, "123456") + + expect(response).to_not be_valid + end + end + +end