diff --git a/app/models/local_census_record.rb b/app/models/local_census_record.rb new file mode 100644 index 000000000..1c2c42d44 --- /dev/null +++ b/app/models/local_census_record.rb @@ -0,0 +1,6 @@ +class LocalCensusRecord < ActiveRecord::Base + validates :document_number, presence: true + validates :document_type, presence: true + validates :date_of_birth, presence: true + validates :postal_code, presence: true +end diff --git a/app/models/officing/residence.rb b/app/models/officing/residence.rb index 6386ce0fd..3f5b184ba 100644 --- a/app/models/officing/residence.rb +++ b/app/models/officing/residence.rb @@ -4,7 +4,7 @@ class Officing::Residence attr_accessor :user, :officer, :document_number, :document_type, :year_of_birth - before_validation :call_census_api + before_validation :retrieve_census_data validates :document_number, presence: true validates :document_type, presence: true @@ -101,8 +101,8 @@ class Officing::Residence private - def call_census_api - @census_api_response = CensusApi.new.call(document_type, document_number) + def retrieve_census_data + @census_api_response = CensusCaller.new.call(document_type, document_number) end def residency_valid? diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb index 7236865c4..760096206 100644 --- a/app/models/poll/voter.rb +++ b/app/models/poll/voter.rb @@ -35,7 +35,7 @@ class Poll end def census_api_response - @census_api_response ||= CensusApi.new.call(document_type, document_number) + @census_api_response ||= CensusCaller.new.call(document_type, document_number) end def fill_stats_fields diff --git a/app/models/signature.rb b/app/models/signature.rb index 88b875894..b354a7a15 100644 --- a/app/models/signature.rb +++ b/app/models/signature.rb @@ -69,7 +69,7 @@ class Signature < ActiveRecord::Base def in_census? document_types.detect do |document_type| - response = CensusApi.new.call(document_type, document_number) + response = CensusCaller.new.call(document_type, document_number) if response.valid? @census_api_response = response true @@ -94,4 +94,4 @@ class Signature < ActiveRecord::Base %w(1 2 3 4) end -end \ No newline at end of file +end diff --git a/app/models/verification/management/document.rb b/app/models/verification/management/document.rb index 578c65a62..c8b9ed6b7 100644 --- a/app/models/verification/management/document.rb +++ b/app/models/verification/management/document.rb @@ -18,7 +18,7 @@ class Verification::Management::Document end def in_census? - response = CensusApi.new.call(document_type, document_number) + response = CensusCaller.new.call(document_type, document_number) response.valid? && valid_age?(response) end diff --git a/app/models/verification/residence.rb b/app/models/verification/residence.rb index 9eaf89555..14f30254f 100644 --- a/app/models/verification/residence.rb +++ b/app/models/verification/residence.rb @@ -5,7 +5,7 @@ class Verification::Residence attr_accessor :user, :document_number, :document_type, :date_of_birth, :postal_code, :terms_of_service - before_validation :call_census_api + before_validation :retrieve_census_data validates :document_number, presence: true validates :document_type, presence: true @@ -61,23 +61,23 @@ class Verification::Residence end def district_code - @census_api_response.district_code + @census_data.district_code end def gender - @census_api_response.gender + @census_data.gender end private - def call_census_api - @census_api_response = CensusApi.new.call(document_type, document_number) + def retrieve_census_data + @census_data = CensusCaller.new.call(document_type, document_number) end def residency_valid? - @census_api_response.valid? && - @census_api_response.postal_code == postal_code && - @census_api_response.date_of_birth == date_of_birth + @census_data.valid? && + @census_data.postal_code == postal_code && + @census_data.date_of_birth == date_of_birth end def clean_document_number diff --git a/db/migrate/20170708174932_create_local_census_records.rb b/db/migrate/20170708174932_create_local_census_records.rb new file mode 100644 index 000000000..640594ded --- /dev/null +++ b/db/migrate/20170708174932_create_local_census_records.rb @@ -0,0 +1,15 @@ +class CreateLocalCensusRecords < ActiveRecord::Migration + def change + create_table :local_census_records do |t| + t.string :document_number, null: false + t.string :document_type, null: false + t.date :date_of_birth, null: false + t.string :postal_code, null: false + t.integer :user_id + + t.timestamps null: false + end + + add_foreign_key :local_census_records, :users, column: :user_id + end +end diff --git a/db/migrate/20170713110317_remove_local_census_record_user_id.rb b/db/migrate/20170713110317_remove_local_census_record_user_id.rb new file mode 100644 index 000000000..9285d849e --- /dev/null +++ b/db/migrate/20170713110317_remove_local_census_record_user_id.rb @@ -0,0 +1,5 @@ +class RemoveLocalCensusRecordUserId < ActiveRecord::Migration + def change + remove_column :local_census_records, :user_id + end +end diff --git a/db/schema.rb b/db/schema.rb index f4c717bd8..de746c5e0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170708225159) do +ActiveRecord::Schema.define(version: 20170713110317) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -484,6 +484,15 @@ ActiveRecord::Schema.define(version: 20170708225159) do add_index "legislation_questions", ["hidden_at"], name: "index_legislation_questions_on_hidden_at", using: :btree add_index "legislation_questions", ["legislation_process_id"], name: "index_legislation_questions_on_legislation_process_id", using: :btree + create_table "local_census_records", force: :cascade do |t| + t.string "document_number", null: false + t.string "document_type", null: false + t.date "date_of_birth", null: false + t.string "postal_code", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "locks", force: :cascade do |t| t.integer "user_id" t.integer "tries", default: 0 diff --git a/lib/census_caller.rb b/lib/census_caller.rb new file mode 100644 index 000000000..d104b03c8 --- /dev/null +++ b/lib/census_caller.rb @@ -0,0 +1,9 @@ +class CensusCaller + + def call(document_type, document_number) + response = CensusApi.new.call(document_type, document_number) + response = LocalCensus.new.call(document_type, document_number) unless response.valid? + + response + end +end diff --git a/lib/local_census.rb b/lib/local_census.rb new file mode 100644 index 000000000..64c1a4052 --- /dev/null +++ b/lib/local_census.rb @@ -0,0 +1,66 @@ +include DocumentParser +class LocalCensus + + def call(document_type, document_number) + record = nil + get_document_number_variants(document_type, document_number).each do |variant| + record = Response.new(get_record(document_type, variant)) + return record if record.valid? + end + record + end + + class Response + def initialize(body) + @body = body + end + + def valid? + @body.present? ? !@body.attributes.values.include?("" || nil) : false + end + + def date_of_birth + @body.date_of_birth + end + + def postal_code + @body.postal_code + end + + def district_code + @body.district_code rescue nil + end + + def gender + case @body.gender + when "VarĂ³n" + "male" + when "Mujer" + "female" + end + rescue NoMethodError + nil + end + + def name + "#{@body.nombre} #{@body.apellido1}" rescue nil + end + + private + + def data + @body.attributes + end + end + + private + + def get_record(document_type, document_number) + LocalCensusRecord.find_by(document_type: document_type, document_number: document_number) + end + + def is_dni?(document_type) + document_type.to_s == "1" + end + +end diff --git a/spec/factories.rb b/spec/factories.rb index d9521847d..7b7e24d97 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,4 +1,11 @@ FactoryGirl.define do + factory :local_census_record, class: 'LocalCensusRecord' do + document_number '12345678A' + document_type 1 + date_of_birth Date.new(1970, 1, 31) + postal_code '28002' + end + sequence(:document_number) { |n| "#{n.to_s.rjust(8, '0')}X" } factory :user do diff --git a/spec/lib/census_caller_spec.rb b/spec/lib/census_caller_spec.rb new file mode 100644 index 000000000..00458a74f --- /dev/null +++ b/spec/lib/census_caller_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +describe CensusCaller do + let(:api) { described_class.new } + + describe '#call' do + it "returns data from local_census_records if census API is not available" do + census_api_response = CensusApi::Response.new({:get_habita_datos_response=>{:get_habita_datos_return=>{:datos_habitante=>{}, :datos_vivienda=>{}}}}) + local_census_response = LocalCensus::Response.new(create(:local_census_record)) + + CensusApi.any_instance.stub(:call).and_return(census_api_response) + LocalCensus.any_instance.stub(:call).and_return(local_census_response) + + allow(CensusApi).to receive(:call).with(1, "12345678A") + allow(LocalCensus).to receive(:call).with(1, "12345678A") + + response = api.call(1, "12345678A") + + expect(response).to eq(local_census_response) + end + + it "returns data from census API if it's available and valid" do + census_api_response = CensusApi::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)) + + CensusApi.any_instance.stub(:call).and_return(census_api_response) + LocalCensus.any_instance.stub(:call).and_return(local_census_response) + + allow(CensusApi).to receive(:call).with(1, "12345678A") + allow(LocalCensus).to receive(:call).with(1, "12345678A") + + response = api.call(1, "12345678A") + + expect(response).to eq(census_api_response) + end + end + +end diff --git a/spec/lib/local_census_spec.rb b/spec/lib/local_census_spec.rb new file mode 100644 index 000000000..074d11a4c --- /dev/null +++ b/spec/lib/local_census_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +describe LocalCensus 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) { nil } + let(:valid_body) { create(:local_census_record) } + + it "returns the response for the first valid variant" do + allow(api).to receive(:get_record).with(1, "00123456").and_return(invalid_body) + allow(api).to receive(:get_record).with(1, "123456").and_return(invalid_body) + expect(api).to receive(:get_record).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(1970, 1, 31)) + end + + it "returns the last failed response" do + expect(api).to receive(:get_record).with(1, "00123456").and_return(invalid_body) + expect(api).to receive(:get_record).with(1, "123456").and_return(invalid_body) + expect(api).to receive(:get_record).with(1, "0123456").and_return(invalid_body) + response = api.call(1, "123456") + + expect(response).to_not be_valid + end + end + +end