Merge pull request #10749 from mfo/US/commune-without-insee
correctif: ETQ administrateur/instructeur, je souhaite que les champs de type commune aient tjr un code insee afin de router de maniere fiable
This commit is contained in:
commit
915779c9b0
10 changed files with 305 additions and 68 deletions
|
@ -3,12 +3,12 @@
|
||||||
class DataSources::CommuneController < ApplicationController
|
class DataSources::CommuneController < ApplicationController
|
||||||
def search
|
def search
|
||||||
if params[:q].present? && params[:q].length > 1
|
if params[:q].present? && params[:q].length > 1
|
||||||
response = fetch_results
|
response = APIGeoService.commune_by_name_or_postal_code(params[:q])
|
||||||
|
|
||||||
if response.success?
|
if response.success?
|
||||||
results = JSON.parse(response.body, symbolize_names: true)
|
results = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
render json: format_results(results)
|
render json: APIGeoService.format_commune_response(results, params[:with_combined_code])
|
||||||
else
|
else
|
||||||
render json: []
|
render json: []
|
||||||
end
|
end
|
||||||
|
@ -16,70 +16,4 @@ class DataSources::CommuneController < ApplicationController
|
||||||
render json: []
|
render json: []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def fetch_results
|
|
||||||
if postal_code?(params[:q])
|
|
||||||
fetch_by_postal_code(params[:q])
|
|
||||||
else
|
|
||||||
fetch_by_name(params[:q])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_by_name(name)
|
|
||||||
Typhoeus.get("#{API_GEO_URL}/communes", params: {
|
|
||||||
type: 'commune-actuelle,arrondissement-municipal',
|
|
||||||
nom: name,
|
|
||||||
boost: 'population',
|
|
||||||
limit: 100
|
|
||||||
}, timeout: 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_by_postal_code(postal_code)
|
|
||||||
Typhoeus.get("#{API_GEO_URL}/communes", params: {
|
|
||||||
type: 'commune-actuelle,arrondissement-municipal',
|
|
||||||
codePostal: postal_code,
|
|
||||||
boost: 'population',
|
|
||||||
limit: 50
|
|
||||||
}, timeout: 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
def postal_code?(string)
|
|
||||||
string.match?(/\A[-+]?\d+\z/) ? true : false
|
|
||||||
end
|
|
||||||
|
|
||||||
def format_results(results)
|
|
||||||
results.reject(&method(:code_metropole?)).flat_map do |result|
|
|
||||||
item = {
|
|
||||||
name: result[:nom].tr("'", '’'),
|
|
||||||
code: result[:code],
|
|
||||||
epci_code: result[:codeEpci],
|
|
||||||
departement_code: result[:codeDepartement]
|
|
||||||
}.compact
|
|
||||||
|
|
||||||
if result[:codesPostaux].present?
|
|
||||||
result[:codesPostaux].map { item.merge(postal_code: _1) }
|
|
||||||
else
|
|
||||||
[item]
|
|
||||||
end.map do |item|
|
|
||||||
if params[:with_combined_code].present?
|
|
||||||
{
|
|
||||||
label: "#{item[:name]} (#{item[:postal_code]})",
|
|
||||||
value: "#{item[:code]}-#{item[:postal_code]}"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
label: "#{item[:name]} (#{item[:postal_code]})",
|
|
||||||
value: item[:code],
|
|
||||||
data: item[:postal_code]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def code_metropole?(result)
|
|
||||||
result[:code].in?(['75056', '13055', '69123'])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,9 @@ class Champs::CommuneChamp < Champs::TextChamp
|
||||||
store_accessor :value_json, :code_departement, :code_postal, :code_region
|
store_accessor :value_json, :code_departement, :code_postal, :code_region
|
||||||
before_save :on_codes_change, if: :should_refresh_after_code_change?
|
before_save :on_codes_change, if: :should_refresh_after_code_change?
|
||||||
|
|
||||||
|
validates :external_id, presence: true, if: -> { validate_champ_value_or_prefill? && value.present? }
|
||||||
|
after_validation :instrument_external_id_error, if: -> { errors.include?(:external_id) }
|
||||||
|
|
||||||
def departement_name
|
def departement_name
|
||||||
APIGeoService.departement_name(code_departement)
|
APIGeoService.departement_name(code_departement)
|
||||||
end
|
end
|
||||||
|
@ -101,4 +104,11 @@ class Champs::CommuneChamp < Champs::TextChamp
|
||||||
def should_refresh_after_code_change?
|
def should_refresh_after_code_change?
|
||||||
!departement? || code_postal_changed? || external_id_changed?
|
!departement? || code_postal_changed? || external_id_changed?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def instrument_external_id_error
|
||||||
|
Sentry.capture_message(
|
||||||
|
"Commune with value and no external id Edge case reached",
|
||||||
|
extra: { request_id: Current.request_id }
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,6 +84,14 @@ class APIGeoService
|
||||||
communes(departement_code).find { _1[:code] == code }&.dig(:name)
|
communes(departement_code).find { _1[:code] == code }&.dig(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def commune_by_name_or_postal_code(query)
|
||||||
|
if postal_code?(query)
|
||||||
|
fetch_by_postal_code(query)
|
||||||
|
else
|
||||||
|
fetch_by_name(query)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def commune_code(departement_code, name)
|
def commune_code(departement_code, name)
|
||||||
communes(departement_code).find { _1[:name] == name }&.dig(:code)
|
communes(departement_code).find { _1[:name] == name }&.dig(:code)
|
||||||
end
|
end
|
||||||
|
@ -215,8 +223,42 @@ class APIGeoService
|
||||||
commune_name(department_code, city_code) || fallback
|
commune_name(department_code, city_code) || fallback
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def format_commune_response(results, with_combined_code)
|
||||||
|
results.reject(&method(:code_metropole?)).flat_map do |result|
|
||||||
|
item = {
|
||||||
|
name: result[:nom].tr("'", '’'),
|
||||||
|
code: result[:code],
|
||||||
|
epci_code: result[:codeEpci],
|
||||||
|
departement_code: result[:codeDepartement]
|
||||||
|
}.compact
|
||||||
|
|
||||||
|
if result[:codesPostaux].present?
|
||||||
|
result[:codesPostaux].map { item.merge(postal_code: _1) }
|
||||||
|
else
|
||||||
|
[item]
|
||||||
|
end.map do |item|
|
||||||
|
if with_combined_code.present?
|
||||||
|
{
|
||||||
|
label: "#{item[:name]} (#{item[:postal_code]})",
|
||||||
|
value: "#{item[:code]}-#{item[:postal_code]}"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label: "#{item[:name]} (#{item[:postal_code]})",
|
||||||
|
value: item[:code],
|
||||||
|
data: item[:postal_code]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def code_metropole?(result)
|
||||||
|
result[:code].in?(['75056', '13055', '69123'])
|
||||||
|
end
|
||||||
|
|
||||||
def communes_by_postal_code_map
|
def communes_by_postal_code_map
|
||||||
Rails.cache.fetch('api_geo_communes', expires_in: 1.day, version: 3) do
|
Rails.cache.fetch('api_geo_communes', expires_in: 1.day, version: 3) do
|
||||||
departements
|
departements
|
||||||
|
@ -251,6 +293,28 @@ class APIGeoService
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def fetch_by_name(name)
|
||||||
|
Typhoeus.get("#{API_GEO_URL}/communes", params: {
|
||||||
|
type: 'commune-actuelle,arrondissement-municipal',
|
||||||
|
nom: name,
|
||||||
|
boost: 'population',
|
||||||
|
limit: 100
|
||||||
|
}, timeout: 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_by_postal_code(postal_code)
|
||||||
|
Typhoeus.get("#{API_GEO_URL}/communes", params: {
|
||||||
|
type: 'commune-actuelle,arrondissement-municipal',
|
||||||
|
codePostal: postal_code,
|
||||||
|
boost: 'population',
|
||||||
|
limit: 50
|
||||||
|
}, timeout: 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
def postal_code?(string)
|
||||||
|
string.match?(/\A[-+]?\d+\z/) ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
def ban_address_schema
|
def ban_address_schema
|
||||||
JSONSchemer.schema(Rails.root.join('app/schemas/adresse-ban.json'))
|
JSONSchemer.schema(Rails.root.join('app/schemas/adresse-ban.json'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Maintenance
|
||||||
|
# some of our Champs::CommuneChamp had been corrupted, ie: missing external_id
|
||||||
|
# this tasks fix this issue
|
||||||
|
class FixChampsCommuneHavingValueButNotExternalIdTask < MaintenanceTasks::Task
|
||||||
|
DEFAULT_INSTRUCTEUR_EMAIL = ENV.fetch('DEFAULT_INSTRUCTEUR_EMAIL') { CONTACT_EMAIL }
|
||||||
|
|
||||||
|
def collection
|
||||||
|
Champs::CommuneChamp.where.not(value: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def process(champ)
|
||||||
|
return if !fixable?(champ)
|
||||||
|
|
||||||
|
response = APIGeoService.commune_by_name_or_postal_code(champ.value)
|
||||||
|
if !response.success?
|
||||||
|
notify("Strange case of existing commune not requestable", champ)
|
||||||
|
else
|
||||||
|
results = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
formated_results = APIGeoService.format_commune_response(results, true)
|
||||||
|
case formated_results.size
|
||||||
|
when 1
|
||||||
|
champ.code = formated_results.first[:value]
|
||||||
|
champ.save!
|
||||||
|
else # otherwise, we can't find the expected departement
|
||||||
|
champ.code_departement = nil
|
||||||
|
champ.code_postal = nil
|
||||||
|
champ.external_id = nil
|
||||||
|
champ.value = nil
|
||||||
|
champ.save(validate: false)
|
||||||
|
|
||||||
|
ask_user_correction(champ)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def count
|
||||||
|
# 2.4M champs, count is not an option
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ask_user_correction(champ)
|
||||||
|
dossier = champ.dossier
|
||||||
|
|
||||||
|
commentaire = CommentaireService.build(current_instructeur, dossier, { body: "Suite à un problème technique, Veuillez re-remplir le champs : #{champ.libelle}" })
|
||||||
|
dossier.flag_as_pending_correction!(commentaire, :incomplete)
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_instructeur
|
||||||
|
user = User.find_by(email: DEFAULT_INSTRUCTEUR_EMAIL)
|
||||||
|
user ||= User.create(email: DEFAULT_INSTRUCTEUR_EMAIL,
|
||||||
|
password: Random.srand,
|
||||||
|
confirmed_at: Time.zone.now,
|
||||||
|
email_verified_at: Time.zone.now)
|
||||||
|
instructeur = user.instructeur
|
||||||
|
instructeur ||= user.create_instructeur!
|
||||||
|
|
||||||
|
instructeur
|
||||||
|
end
|
||||||
|
|
||||||
|
def fixable?(champ)
|
||||||
|
champ.value.present? && [champ.dossier.en_instruction? || champ.dossier.en_construction?]
|
||||||
|
end
|
||||||
|
|
||||||
|
def notify(message, champ) = Sentry.capture_message(message, extra: { champ: })
|
||||||
|
end
|
||||||
|
end
|
|
@ -274,3 +274,8 @@ CRON_JOBS_DISABLED=""
|
||||||
|
|
||||||
# optional license key for lightgallery
|
# optional license key for lightgallery
|
||||||
VITE_LIGHTGALLERY_LICENSE_KEY = ""
|
VITE_LIGHTGALLERY_LICENSE_KEY = ""
|
||||||
|
|
||||||
|
# Email used to find the Instructeur who fixes data on production.
|
||||||
|
# This email will be visible to users whom dossier had been fixed by our maintenance_tasks
|
||||||
|
# By default we use CONTACT_EMAIL, but you can customize it
|
||||||
|
MAINTENANCE_INSTRUCTEUR_EMAIL=""
|
||||||
|
|
|
@ -20,3 +20,9 @@ user = User.create!(
|
||||||
)
|
)
|
||||||
user.create_instructeur!
|
user.create_instructeur!
|
||||||
user.create_administrateur!
|
user.create_administrateur!
|
||||||
|
|
||||||
|
user_fixer User.create(email: ENV.fetch('DEFAULT_INSTRUCTEUR_EMAIL') { CONTACT_EMAIL },
|
||||||
|
password: Random.srand,
|
||||||
|
confirmed_at: Time.zone.now,
|
||||||
|
email_verified_at: Time.zone.now)
|
||||||
|
user_fixer.create_instructeur!
|
||||||
|
|
41
spec/fixtures/cassettes/fix-champs-commune-with-more-than-one-results.yml
vendored
Normal file
41
spec/fixtures/cassettes/fix-champs-commune-with-more-than-one-results.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
http_interactions:
|
||||||
|
- request:
|
||||||
|
method: get
|
||||||
|
uri: https://geo.api.gouv.fr/communes?boost=population&limit=100&nom=Marseille&type=commune-actuelle,arrondissement-municipal
|
||||||
|
body:
|
||||||
|
encoding: US-ASCII
|
||||||
|
string: ''
|
||||||
|
headers:
|
||||||
|
User-Agent:
|
||||||
|
- demarches-simplifiees.fr
|
||||||
|
Expect:
|
||||||
|
- ''
|
||||||
|
response:
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: ''
|
||||||
|
headers:
|
||||||
|
Server:
|
||||||
|
- nginx/1.10.3 (Ubuntu)
|
||||||
|
Date:
|
||||||
|
- Fri, 06 Sep 2024 07:25:27 GMT
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
Content-Length:
|
||||||
|
- '3583'
|
||||||
|
Vary:
|
||||||
|
- Accept-Encoding
|
||||||
|
- Origin
|
||||||
|
X-Powered-By:
|
||||||
|
- Express
|
||||||
|
Etag:
|
||||||
|
- W/"dff-vG1Dx3YDZB27TTb5VLsh9AEwHbw"
|
||||||
|
Strict-Transport-Security:
|
||||||
|
- max-age=15552000
|
||||||
|
body:
|
||||||
|
encoding: ASCII-8BIT
|
||||||
|
string: !binary |-
|
||||||
|
W3sibm9tIjoiTWFyc2VpbGxlIiwiY29kZSI6IjEzMDU1IiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJzaXJlbiI6IjIxMTMwMDU1MyIsImNvZGVFcGNpIjoiMjAwMDU0ODA3IiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDAxIiwiMTMwMDIiLCIxMzAwMyIsIjEzMDA0IiwiMTMwMDUiLCIxMzAwNiIsIjEzMDA3IiwiMTMwMDgiLCIxMzAwOSIsIjEzMDEwIiwiMTMwMTEiLCIxMzAxMiIsIjEzMDEzIiwiMTMwMTQiLCIxMzAxNSIsIjEzMDE2Il0sInBvcHVsYXRpb24iOjg3MzA3NiwiX3Njb3JlIjo0Ljg4ODM3MDE4MzkyOTEwMn0seyJub20iOiJNYXJzZWlsbGV0dGUiLCJjb2RlIjoiMTEyMjAiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMSIsInNpcmVuIjoiMjExMTAyMjA3IiwiY29kZUVwY2kiOiIyMDAwMzU3MTUiLCJjb2RlUmVnaW9uIjoiNzYiLCJjb2Rlc1Bvc3RhdXgiOlsiMTE4MDAiXSwicG9wdWxhdGlvbiI6NzAwLCJfc2NvcmUiOjAuNjE1Njg0Njg2ODA1MzMxN30seyJub20iOiJNYXJzZWlsbGUgMTNlIEFycm9uZGlzc2VtZW50IiwiY29kZSI6IjEzMjEzIiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJjb2RlUmVnaW9uIjoiOTMiLCJjb2Rlc1Bvc3RhdXgiOlsiMTMwMTMiXSwicG9wdWxhdGlvbiI6OTIyNjEsIl9zY29yZSI6MC41OTc4NjI1OTk0MDkxODg0fSx7Im5vbSI6Ik1hcnNlaWxsZSA4ZSBBcnJvbmRpc3NlbWVudCIsImNvZGUiOiIxMzIwOCIsImNvZGVEZXBhcnRlbWVudCI6IjEzIiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDA4Il0sInBvcHVsYXRpb24iOjgyNjA5LCJfc2NvcmUiOjAuNTY3ODQ4MzQ4OTM5Nzg3NX0seyJub20iOiJNYXJzZWlsbGUgMTVlIEFycm9uZGlzc2VtZW50IiwiY29kZSI6IjEzMjE1IiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJjb2RlUmVnaW9uIjoiOTMiLCJjb2Rlc1Bvc3RhdXgiOlsiMTMwMTUiXSwicG9wdWxhdGlvbiI6Nzk2NTYsIl9zY29yZSI6MC41NTg2NjU1ODA0MzIxMDYxfSx7Im5vbSI6Ik1hcnNlaWxsZSA5ZSBBcnJvbmRpc3NlbWVudCIsImNvZGUiOiIxMzIwOSIsImNvZGVEZXBhcnRlbWVudCI6IjEzIiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDA5Il0sInBvcHVsYXRpb24iOjc3MTA2LCJfc2NvcmUiOjAuNTUwNzM1OTk3MDYxMDk3OH0seyJub20iOiJNYXJzZWlsbGUgMTJlIEFycm9uZGlzc2VtZW50IiwiY29kZSI6IjEzMjEyIiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJjb2RlUmVnaW9uIjoiOTMiLCJjb2Rlc1Bvc3RhdXgiOlsiMTMwMTIiXSwicG9wdWxhdGlvbiI6NjMxMDgsIl9zY29yZSI6MC41MDcyMDcyNDg4MTUwNjg1fSx7Im5vbSI6Ik1hcnNlaWxsZSAxNGUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMTQiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAxNCJdLCJwb3B1bGF0aW9uIjo1OTk0OCwiX3Njb3JlIjowLjQ5NzM4MDc4NDcxNjA5MzU0fSx7Im5vbSI6Ik1hcnNlaWxsZSAxMGUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMTAiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAxMCJdLCJwb3B1bGF0aW9uIjo1OTAwMiwiX3Njb3JlIjowLjQ5NDQzOTA2NDc2NzQ3NjM0fSx7Im5vbSI6Ik1hcnNlaWxsZSAxMWUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMTEiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAxMSJdLCJwb3B1bGF0aW9uIjo1NzkyNCwiX3Njb3JlIjowLjQ5MTA4Njg3MjI2Nzg4OTMzfSx7Im5vbSI6Ik1hcnNlaWxsZSAzZSBBcnJvbmRpc3NlbWVudCIsImNvZGUiOiIxMzIwMyIsImNvZGVEZXBhcnRlbWVudCI6IjEzIiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDAzIl0sInBvcHVsYXRpb24iOjUzMTE1LCJfc2NvcmUiOjAuNDc2MTMyNjEwOTIyMzI4OTV9LHsibm9tIjoiTWFyc2VpbGxlcy1sw6hzLUF1YmlnbnkiLCJjb2RlIjoiMTgxMzkiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxOCIsInNpcmVuIjoiMjExODAxMzk0IiwiY29kZUVwY2kiOiIyMDAwMTE3ODEiLCJjb2RlUmVnaW9uIjoiMjQiLCJjb2Rlc1Bvc3RhdXgiOlsiMTgzMjAiXSwicG9wdWxhdGlvbiI6NjQ5LCJfc2NvcmUiOjAuNDcyMzE5NTc0NzcwNjA2OH0seyJub20iOiJNYXJzZWlsbGUgNGUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMDQiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAwNCJdLCJwb3B1bGF0aW9uIjo1MDA2OCwiX3Njb3JlIjowLjQ2NjY1NzUzNjIwNDEwODR9LHsibm9tIjoiTWFyc2VpbGxlIDVlIEFycm9uZGlzc2VtZW50IiwiY29kZSI6IjEzMjA1IiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJjb2RlUmVnaW9uIjoiOTMiLCJjb2Rlc1Bvc3RhdXgiOlsiMTMwMDUiXSwicG9wdWxhdGlvbiI6NDU0NDksIl9zY29yZSI6MC40NTIyOTQxMDY1NjA3MDE1N30seyJub20iOiJNYXJzZWlsbGUgNmUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMDYiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAwNiJdLCJwb3B1bGF0aW9uIjozOTY0NywiX3Njb3JlIjowLjQzNDI1MTk3MjE2MTI1NDMzfSx7Im5vbSI6Ik1hcnNlaWxsZSA3ZSBBcnJvbmRpc3NlbWVudCIsImNvZGUiOiIxMzIwNyIsImNvZGVEZXBhcnRlbWVudCI6IjEzIiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDA3Il0sInBvcHVsYXRpb24iOjM0NjMzLCJfc2NvcmUiOjAuNDE4NjYwMjM0NTA1NDc1N30seyJub20iOiJNYXJzZWlsbGUgMWVyIEFycm9uZGlzc2VtZW50IiwiY29kZSI6IjEzMjAxIiwiY29kZURlcGFydGVtZW50IjoiMTMiLCJjb2RlUmVnaW9uIjoiOTMiLCJjb2Rlc1Bvc3RhdXgiOlsiMTMwMDEiXSwicG9wdWxhdGlvbiI6Mzk0MzYsIl9zY29yZSI6MC4zODc5OTk5NzIyNDQ0ODU1N30seyJub20iOiJNYXJzZWlsbGUgMmUgQXJyb25kaXNzZW1lbnQiLCJjb2RlIjoiMTMyMDIiLCJjb2RlRGVwYXJ0ZW1lbnQiOiIxMyIsImNvZGVSZWdpb24iOiI5MyIsImNvZGVzUG9zdGF1eCI6WyIxMzAwMiJdLCJwb3B1bGF0aW9uIjoyMzYyNywiX3Njb3JlIjowLjM4NDQzNTUzMDc0ODA5NjJ9LHsibm9tIjoiTWFyc2VpbGxlIDE2ZSBBcnJvbmRpc3NlbWVudCIsImNvZGUiOiIxMzIxNiIsImNvZGVEZXBhcnRlbWVudCI6IjEzIiwiY29kZVJlZ2lvbiI6IjkzIiwiY29kZXNQb3N0YXV4IjpbIjEzMDE2Il0sInBvcHVsYXRpb24iOjE1NDg3LCJfc2NvcmUiOjAuMzU5MTIzMDU2NzcxNjIyNjV9LHsibm9tIjoiTWFyc2VpbGxlLWVuLUJlYXV2YWlzaXMiLCJjb2RlIjoiNjAzODciLCJjb2RlRGVwYXJ0ZW1lbnQiOiI2MCIsInNpcmVuIjoiMjE2MDAzODMwIiwiY29kZUVwY2kiOiIyNDYwMDA4NDgiLCJjb2RlUmVnaW9uIjoiMzIiLCJjb2Rlc1Bvc3RhdXgiOlsiNjA2OTAiXSwicG9wdWxhdGlvbiI6MTQ0MywiX3Njb3JlIjowLjMwMTMyNjM4Mzc4MTY5NjZ9XQ==
|
||||||
|
recorded_at: Fri, 06 Sep 2024 07:25:27 GMT
|
||||||
|
recorded_with: VCR 6.2.0
|
41
spec/fixtures/cassettes/fix-champs-commune-with-one-results.yml
vendored
Normal file
41
spec/fixtures/cassettes/fix-champs-commune-with-one-results.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
http_interactions:
|
||||||
|
- request:
|
||||||
|
method: get
|
||||||
|
uri: https://geo.api.gouv.fr/communes?boost=population&limit=100&nom=Coye-la-For%C3%AAt&type=commune-actuelle,arrondissement-municipal
|
||||||
|
body:
|
||||||
|
encoding: US-ASCII
|
||||||
|
string: ''
|
||||||
|
headers:
|
||||||
|
User-Agent:
|
||||||
|
- demarches-simplifiees.fr
|
||||||
|
Expect:
|
||||||
|
- ''
|
||||||
|
response:
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: ''
|
||||||
|
headers:
|
||||||
|
Server:
|
||||||
|
- nginx/1.10.3 (Ubuntu)
|
||||||
|
Date:
|
||||||
|
- Fri, 06 Sep 2024 07:25:28 GMT
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
Content-Length:
|
||||||
|
- '197'
|
||||||
|
Vary:
|
||||||
|
- Accept-Encoding
|
||||||
|
- Origin
|
||||||
|
X-Powered-By:
|
||||||
|
- Express
|
||||||
|
Etag:
|
||||||
|
- W/"c5-7Mng3tlbwfBH/m/FGIzzGMvfw/8"
|
||||||
|
Strict-Transport-Security:
|
||||||
|
- max-age=15552000
|
||||||
|
body:
|
||||||
|
encoding: ASCII-8BIT
|
||||||
|
string: !binary |-
|
||||||
|
W3sibm9tIjoiQ295ZS1sYS1Gb3LDqnQiLCJjb2RlIjoiNjAxNzIiLCJjb2RlRGVwYXJ0ZW1lbnQiOiI2MCIsInNpcmVuIjoiMjE2MDAxNzE5IiwiY29kZUVwY2kiOiIyNDYwMDA3NjQiLCJjb2RlUmVnaW9uIjoiMzIiLCJjb2Rlc1Bvc3RhdXgiOlsiNjA1ODAiXSwicG9wdWxhdGlvbiI6Mzk1MCwiX3Njb3JlIjowLjA3MTQ1MzgwNDc4MTQ5OTQ2fV0=
|
||||||
|
recorded_at: Fri, 06 Sep 2024 07:25:28 GMT
|
||||||
|
recorded_with: VCR 6.2.0
|
|
@ -28,6 +28,22 @@ describe Champs::CommuneChamp do
|
||||||
expect(champ.for_export(:departement)).to eq '63 – Puy-de-Dôme'
|
expect(champ.for_export(:departement)).to eq '63 – Puy-de-Dôme'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with tricky bug (should not happen, but it happens)' do
|
||||||
|
let(:champ) do
|
||||||
|
described_class.new(stable_id: 99, dossier:).tap do |champ|
|
||||||
|
champ.external_id = ''
|
||||||
|
champ.value = 'Gagny'
|
||||||
|
champ.run_callbacks(:save)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails' do
|
||||||
|
expect(champ).to receive(:instrument_external_id_error)
|
||||||
|
expect(champ.validate(:champs_public_value)).to be_falsey
|
||||||
|
expect(champ.errors).to include('external_id')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with code' do
|
context 'with code' do
|
||||||
let(:champ) do
|
let(:champ) do
|
||||||
described_class.new(stable_id: 99, dossier:).tap do |champ|
|
described_class.new(stable_id: 99, dossier:).tap do |champ|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
module Maintenance
|
||||||
|
RSpec.describe FixChampsCommuneHavingValueButNotExternalIdTask do
|
||||||
|
describe "#process" do
|
||||||
|
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }]) }
|
||||||
|
let(:dossier) { create(:dossier, state, :with_populated_champs, procedure:) }
|
||||||
|
let(:champ) { dossier.champs.first }
|
||||||
|
subject(:process) { described_class.process(champ) }
|
||||||
|
|
||||||
|
context 'when search find one result', vcr: { cassette_name: 'fix-champs-commune-with-one-results' } do
|
||||||
|
let(:state) { [:en_instruction, :en_construction].sample }
|
||||||
|
let!(:expected_external_id) { champ.external_id }
|
||||||
|
before { champ.update_column(:external_id, nil) }
|
||||||
|
|
||||||
|
it "backfill external_id" do
|
||||||
|
expect { subject }.to change { champ.reload.external_id }.from(nil).to(expected_external_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when search find 0 or more than 1 results', vcr: { cassette_name: 'fix-champs-commune-with-more-than-one-results' } do
|
||||||
|
let(:instructeur) { create(:instructeur, user: create(:user, email: Maintenance::FixChampsCommuneHavingValueButNotExternalIdTask::DEFAULT_INSTRUCTEUR_EMAIL)) }
|
||||||
|
before do
|
||||||
|
instructeur
|
||||||
|
champ.update_columns(external_id: nil, value: 'Marseille') # more than one marseille in france
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'en_instruction (go back to en_construction!), send comment' do
|
||||||
|
let(:state) { [:en_instruction, :en_construction].sample }
|
||||||
|
|
||||||
|
it 'flags as pending correction' do
|
||||||
|
expect { subject }.to change { champ.reload.value }.from('Marseille').to(nil)
|
||||||
|
expect(Commentaire.first.instructeur).to eq(instructeur)
|
||||||
|
expect(champ.dossier.state).to eq("en_construction")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when champs will passthru validator (ie: state is brouillon)' \
|
||||||
|
'or champ belongs to dossier.termine (ie: state is accepte, refuse or classer_sans_suite)' do
|
||||||
|
let(:state) { [:brouillon, :accepte, :refuse, :sans_suite].sample }
|
||||||
|
|
||||||
|
it "skips backfill as well as asks for correction" do
|
||||||
|
expect { subject }.not_to change { champ.reload }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue