refactor(address): use directly BAN data
This commit is contained in:
parent
0b3a0d5840
commit
20307f1d21
11 changed files with 85 additions and 124 deletions
|
@ -1,2 +1,3 @@
|
|||
= render Dsfr::ComboboxComponent.new form: @form, url: data_sources_data_source_adresse_path, selected: @champ.value, allows_custom_value: true, input_html_options: { name: :value, id: @champ.input_id, class: 'fr-select', describedby: @champ.describedby_id } do
|
||||
= @form.hidden_field :external_id, data: { value_slot: 'value' }
|
||||
= @form.hidden_field :feature, data: { value_slot: 'data' }
|
||||
|
|
|
@ -26,7 +26,7 @@ class DataSources::AdresseController < ApplicationController
|
|||
{
|
||||
label: _1[:properties][:label],
|
||||
value: _1[:properties][:label],
|
||||
data: _1[:properties]
|
||||
data: _1
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -401,7 +401,7 @@ module Instructeurs
|
|||
def champs_private_params
|
||||
champs_params = params.require(:dossier).permit(champs_private_attributes: [
|
||||
:id, :value, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :code_departement, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :code_departement, value: []]
|
||||
champs_attributes: [:id, :_destroy, :value, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :code_departement, :feature, value: []]
|
||||
])
|
||||
champs_params[:champs_private_all_attributes] = champs_params.delete(:champs_private_attributes) || {}
|
||||
champs_params
|
||||
|
|
|
@ -488,6 +488,7 @@ module Users
|
|||
:code_departement,
|
||||
:accreditation_number,
|
||||
:accreditation_birthdate,
|
||||
:feature,
|
||||
value: []
|
||||
])
|
||||
champs_params[:champs_public_all_attributes] = champs_params.delete(:champs_public_attributes) || {}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
require 'json_schemer'
|
||||
|
||||
class APIAddress::AddressAdapter
|
||||
class InvalidSchemaError < ::StandardError
|
||||
def initialize(errors)
|
||||
super(errors.map(&:to_json).join("\n"))
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(search_term)
|
||||
@search_term = search_term
|
||||
end
|
||||
|
||||
def to_params
|
||||
result = Geocoder.search(@search_term, limit: 1).first
|
||||
if result.present? && result.national_address == @search_term
|
||||
feature = result.data['features'].first
|
||||
if schemer.valid?(feature)
|
||||
{
|
||||
label: result.national_address,
|
||||
type: result.result_type,
|
||||
street_address: result.street_address,
|
||||
street_number: result.street_number,
|
||||
street_name: result.street_name,
|
||||
postal_code: result.postal_code.presence || "",
|
||||
city_name: result.city_name,
|
||||
city_code: result.city_code,
|
||||
department_name: result.department_name,
|
||||
department_code: result.department_code,
|
||||
region_name: result.region_name,
|
||||
region_code: result.region_code,
|
||||
geometry: result.geometry
|
||||
}
|
||||
else
|
||||
errors = schemer.validate(feature).to_a
|
||||
raise InvalidSchemaError.new(errors)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def schemer
|
||||
@schemer ||= JSONSchemer.schema(Rails.root.join('app/schemas/adresse-ban.json'))
|
||||
end
|
||||
end
|
|
@ -3,6 +3,18 @@ class Champs::AddressChamp < Champs::TextChamp
|
|||
data.present?
|
||||
end
|
||||
|
||||
def feature
|
||||
''
|
||||
end
|
||||
|
||||
def feature=(value)
|
||||
return if value.blank?
|
||||
feature = JSON.parse(value)
|
||||
self.data = APIGeoService.parse_ban_address(feature)
|
||||
rescue JSON::ParserError
|
||||
self.data = nil
|
||||
end
|
||||
|
||||
def address
|
||||
full_address? ? data : nil
|
||||
end
|
||||
|
@ -13,7 +25,7 @@ class Champs::AddressChamp < Champs::TextChamp
|
|||
|
||||
def search_terms
|
||||
if full_address?
|
||||
[data['label'], data['departement'], data['region'], data['city']]
|
||||
[data['label'], data['department_name'], data['region_name'], data['city_name']]
|
||||
else
|
||||
[address_label]
|
||||
end
|
||||
|
@ -35,45 +47,48 @@ class Champs::AddressChamp < Champs::TextChamp
|
|||
address_label
|
||||
end
|
||||
|
||||
def fetch_external_data?
|
||||
true
|
||||
def code_departement
|
||||
if full_address?
|
||||
address.fetch('department_code')
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_external_data
|
||||
APIAddress::AddressAdapter.new(external_id).to_params
|
||||
def code_region
|
||||
if full_address?
|
||||
address.fetch('region_code')
|
||||
end
|
||||
end
|
||||
|
||||
def departement_name
|
||||
APIGeoService.departement_name(address.fetch('department_code'))
|
||||
APIGeoService.departement_name(code_departement)
|
||||
end
|
||||
|
||||
def departement_code_and_name
|
||||
if full_address?
|
||||
"#{address.fetch('department_code')} – #{departement_name}"
|
||||
"#{code_departement} – #{departement_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def departement
|
||||
if full_address?
|
||||
{ code: address.fetch('department_code'), name: departement_name }
|
||||
{ code: code_departement, name: departement_name }
|
||||
end
|
||||
end
|
||||
|
||||
def commune_name
|
||||
if full_address?
|
||||
"#{APIGeoService.commune_name(address.fetch('department_code'), address['city_code'])} (#{address['postal_code']})"
|
||||
"#{APIGeoService.commune_name(code_departement, address['city_code'])} (#{address['postal_code']})"
|
||||
end
|
||||
end
|
||||
|
||||
def commune
|
||||
if full_address?
|
||||
department_code = address.fetch('department_code')
|
||||
city_code = address.fetch('city_code')
|
||||
city_name = address.fetch('city_name')
|
||||
postal_code = address.fetch('postal_code')
|
||||
|
||||
commune_name = APIGeoService.commune_name(department_code, city_code)
|
||||
commune_code = APIGeoService.commune_code(department_code, city_name)
|
||||
commune_name = APIGeoService.commune_name(code_departement, city_code)
|
||||
commune_code = APIGeoService.commune_code(code_departement, city_name)
|
||||
|
||||
if commune_name.present?
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ class Champs::DepartementChamp < Champs::TextChamp
|
|||
end
|
||||
|
||||
def code_region
|
||||
APIGeoService.region_code_by_departement(name)
|
||||
APIGeoService.region_code_by_departement(code)
|
||||
end
|
||||
|
||||
def value=(code)
|
||||
|
|
|
@ -44,7 +44,7 @@ class Champs::EpciChamp < Champs::TextChamp
|
|||
end
|
||||
|
||||
def code_region
|
||||
APIGeoService.region_code_by_departement(departement_name)
|
||||
APIGeoService.region_code_by_departement(code_departement)
|
||||
end
|
||||
|
||||
def selected
|
||||
|
|
|
@ -34,9 +34,9 @@ class APIGeoService
|
|||
regions.find { _1[:name] == name }&.dig(:code)
|
||||
end
|
||||
|
||||
def region_code_by_departement(name)
|
||||
return if name.nil?
|
||||
departements.find { _1[:name] == name }&.dig(:region_code)
|
||||
def region_code_by_departement(code)
|
||||
return if code.nil?
|
||||
departements.find { _1[:code] == code }&.dig(:region_code)
|
||||
end
|
||||
|
||||
def departements
|
||||
|
@ -81,6 +81,42 @@ class APIGeoService
|
|||
communes(departement_code).find { _1[:name] == name }&.dig(:code)
|
||||
end
|
||||
|
||||
def parse_ban_address(feature)
|
||||
return unless ban_address_schema.valid?(feature)
|
||||
|
||||
properties = feature.fetch('properties')
|
||||
city_code = properties.fetch('citycode')
|
||||
|
||||
territory = if properties['context'].present?
|
||||
department_code = properties.fetch('context').split(',').first
|
||||
region_code = region_code_by_departement(department_code)
|
||||
|
||||
{
|
||||
department_name: departement_name(department_code),
|
||||
department_code:,
|
||||
region_name: region_name(region_code),
|
||||
region_code:,
|
||||
city_name: commune_name(department_code, city_code),
|
||||
city_code:
|
||||
}
|
||||
else
|
||||
{
|
||||
city_name: properties['city'],
|
||||
city_code:
|
||||
}
|
||||
end
|
||||
|
||||
{
|
||||
label: properties.fetch('label'),
|
||||
type: properties.fetch('type'),
|
||||
street_address: properties.fetch('name'),
|
||||
postal_code: properties.fetch('postcode'),
|
||||
street_number: properties['housenumber'],
|
||||
street_name: properties['street'],
|
||||
geometry: feature['geometry']
|
||||
}.merge(territory)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def communes_by_postal_code_map
|
||||
|
@ -114,5 +150,11 @@ class APIGeoService
|
|||
'EN' => { 'XK' => 'Kosovo' }
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ban_address_schema
|
||||
JSONSchemer.schema(Rails.root.join('app/schemas/adresse-ban.json'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
- if champ.to_s.present?
|
||||
= format_text_value(champ.to_s)
|
||||
%p= champ.to_s
|
||||
- if champ.full_address?
|
||||
Code INSEE :
|
||||
= champ.commune&.fetch(:code)
|
||||
%p.fr-text--sm
|
||||
Code INSEE :
|
||||
= champ.commune&.fetch(:code)
|
||||
%p.fr-text--sm
|
||||
Departement :
|
||||
= champ.departement_code_and_name
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
describe APIAddress::AddressAdapter do
|
||||
let(:search_term) { 'Paris' }
|
||||
let(:adapter) { described_class.new(search_term) }
|
||||
let(:status) { 200 }
|
||||
subject { adapter.to_params }
|
||||
|
||||
before do
|
||||
Geocoder.configure(lookup: :ban_data_gouv_fr, use_https: true)
|
||||
stub_request(:get, /https:\/\/api-adresse.data.gouv.fr\/search/)
|
||||
.to_return(body: body, status: status)
|
||||
end
|
||||
|
||||
after do
|
||||
Geocoder.configure(lookup: :test)
|
||||
end
|
||||
|
||||
context "when responds with valid schema" do
|
||||
let(:body) { File.read('spec/fixtures/files/api_address/address.json') }
|
||||
|
||||
it '#to_params returns a valid' do
|
||||
expect(subject).to be_an_instance_of(Hash)
|
||||
expect(subject[:city_name]).to eq(search_term)
|
||||
expect(subject[:city_code]).to eq('75056')
|
||||
end
|
||||
end
|
||||
|
||||
context "when responds with an address which is not a direct match to search term" do
|
||||
let(:body) { File.read('spec/fixtures/files/api_address/address.json') }
|
||||
let(:search_term) { 'Lyon' }
|
||||
|
||||
it '#to_params ignores the response' do
|
||||
expect(subject).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when responds with invalid schema" do
|
||||
let(:body) { File.read('spec/fixtures/files/api_address/address_invalid.json') }
|
||||
|
||||
it '#to_params raise exception' do
|
||||
expect { subject }.to raise_exception(APIAddress::AddressAdapter::InvalidSchemaError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when responds without postcode" do
|
||||
let(:body) {
|
||||
json = JSON.parse(File.read('spec/fixtures/files/api_address/address.json'))
|
||||
json["features"][0]["properties"].delete("postcode")
|
||||
json.to_json
|
||||
}
|
||||
|
||||
it "#to_params default to an empty postcode" do
|
||||
expect(subject[:postal_code]).to eq("")
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue