Merge pull request #8783 from tchak/improuve-champ-commune
refactor(commune): choisir la commune par son code postal
This commit is contained in:
commit
acc8584cdf
29 changed files with 735 additions and 365 deletions
|
@ -1,2 +1,17 @@
|
||||||
class EditableChamp::CommunesComponent < EditableChamp::ComboSearchComponent
|
class EditableChamp::CommunesComponent < EditableChamp::EditableChampBaseComponent
|
||||||
|
include ApplicationHelper
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def commune_options
|
||||||
|
@champ.communes.map { ["#{_1[:name]} (#{_1[:postal_code]})", _1[:code]] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def code_postal_input_id
|
||||||
|
"#{@champ.input_id}-code_postal"
|
||||||
|
end
|
||||||
|
|
||||||
|
def commune_select_options
|
||||||
|
{ selected: @champ.selected }.merge(@champ.mandatory? ? { prompt: '' } : { include_blank: '' })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
postal_code: Postal code of the municipality
|
||||||
|
not_found: No municipality found for postal code %{postal_code}
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
postal_code: Code postal de la commune
|
||||||
|
not_found: Aucune commune trouvée pour le code postal %{postal_code}
|
|
@ -1,12 +1,13 @@
|
||||||
- render_parent
|
%label.notice{ for: code_postal_input_id }= t('.postal_code')
|
||||||
= @form.hidden_field :value
|
= @form.text_field :code_postal, required: @champ.required?, id: code_postal_input_id, class: "width-33-desktop width-100-mobile small-margin"
|
||||||
= @form.hidden_field :external_id
|
- if @champ.code_postal_with_fallback?
|
||||||
= @form.hidden_field :departement
|
- if commune_options.empty?
|
||||||
= @form.hidden_field :code_departement
|
.fr-error-text.mb-4= t('.not_found', postal_code: @champ.code_postal_with_fallback)
|
||||||
= react_component("ComboCommunesSearch",
|
- elsif commune_options.size <= 3
|
||||||
required: @champ.required?,
|
%fieldset.radios
|
||||||
id: @champ.input_id,
|
- commune_options.each.with_index do |(option, value), index|
|
||||||
classNameDepartement: "width-33-desktop width-100-mobile",
|
%label
|
||||||
className: "width-66-desktop width-100-mobile",
|
= @form.radio_button :value, value, checked: @champ.selected == value, id: index == 0 ? @champ.input_id : nil
|
||||||
describedby: @champ.describedby_id,
|
= option
|
||||||
**react_combo_props)
|
- else
|
||||||
|
= @form.select :value, commune_options, commune_select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||||
|
|
|
@ -326,8 +326,8 @@ module Instructeurs
|
||||||
|
|
||||||
def champs_private_params
|
def champs_private_params
|
||||||
champs_params = params.require(:dossier).permit(champs_private_attributes: [
|
champs_params = params.require(:dossier).permit(champs_private_attributes: [
|
||||||
:id, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :departement, :code_departement, :value, value: [],
|
:id, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :code_departement, :value, value: [],
|
||||||
champs_attributes: [:id, :_destroy, :value, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :departement, :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_params[:champs_private_all_attributes] = champs_params.delete(:champs_private_attributes) || {}
|
champs_params[:champs_private_all_attributes] = champs_params.delete(:champs_private_attributes) || {}
|
||||||
champs_params
|
champs_params
|
||||||
|
|
|
@ -387,7 +387,7 @@ module Users
|
||||||
|
|
||||||
def champs_public_params
|
def champs_public_params
|
||||||
champs_params = params.require(:dossier).permit(champs_public_attributes: [
|
champs_params = params.require(:dossier).permit(champs_public_attributes: [
|
||||||
:id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: [],
|
:id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :code_departement, value: [],
|
||||||
champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: []]
|
champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: []]
|
||||||
])
|
])
|
||||||
champs_params[:champs_public_all_attributes] = champs_params.delete(:champs_public_attributes) || {}
|
champs_params[:champs_public_all_attributes] = champs_params.delete(:champs_public_attributes) || {}
|
||||||
|
|
|
@ -404,7 +404,16 @@ type Commune {
|
||||||
Le code INSEE
|
Le code INSEE
|
||||||
"""
|
"""
|
||||||
code: String!
|
code: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Le nom de la commune
|
||||||
|
"""
|
||||||
name: String!
|
name: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Le code postal
|
||||||
|
"""
|
||||||
|
postalCode: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommuneChamp implements Champ {
|
type CommuneChamp implements Champ {
|
||||||
|
|
|
@ -3,29 +3,20 @@ module Types::Champs
|
||||||
implements Types::ChampType
|
implements Types::ChampType
|
||||||
|
|
||||||
class CommuneType < Types::BaseObject
|
class CommuneType < Types::BaseObject
|
||||||
field :name, String, null: false
|
field :name, String, "Le nom de la commune", null: false
|
||||||
field :code, String, "Le code INSEE", null: false
|
field :code, String, "Le code INSEE", null: false
|
||||||
|
field :postal_code, String, "Le code postal", null: true, method: :code_postal
|
||||||
end
|
end
|
||||||
|
|
||||||
field :commune, CommuneType, null: true
|
field :commune, CommuneType, null: true
|
||||||
field :departement, Types::Champs::DepartementChampType::DepartementType, null: true
|
field :departement, Types::Champs::DepartementChampType::DepartementType, null: true
|
||||||
|
|
||||||
def commune
|
def commune
|
||||||
if object.code?
|
object if object.code?
|
||||||
{
|
|
||||||
name: object.to_s,
|
|
||||||
code: object.code
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def departement
|
def departement
|
||||||
if object.departement?
|
object.departement if object.departement?
|
||||||
{
|
|
||||||
name: object.name_departement,
|
|
||||||
code: object.code_departement
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { QueryClientProvider } from 'react-query';
|
|
||||||
import { matchSorter } from 'match-sorter';
|
|
||||||
|
|
||||||
import ComboSearch, { ComboSearchProps } from './ComboSearch';
|
|
||||||
import { queryClient } from './shared/queryClient';
|
|
||||||
import { ComboDepartementsSearch } from './ComboDepartementsSearch';
|
|
||||||
import { useHiddenField, groupId } from './shared/hooks';
|
|
||||||
|
|
||||||
type CommuneResult = { code: string; nom: string; codesPostaux: string[] };
|
|
||||||
|
|
||||||
// Avoid hiding similar matches for precise queries (like "Sainte Marie")
|
|
||||||
function searchResultsLimit(term: string) {
|
|
||||||
return term.length > 5 ? 10 : 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
function expandResultsWithMultiplePostalCodes(term: string, result: unknown) {
|
|
||||||
const results = result as CommuneResult[];
|
|
||||||
// A single result may have several associated postal codes.
|
|
||||||
// To make the search results more precise, we want to generate
|
|
||||||
// an actual result for each postal code.
|
|
||||||
const expandedResults = results.flatMap((result) =>
|
|
||||||
result.codesPostaux.map((codePostal) => ({
|
|
||||||
...result,
|
|
||||||
codesPostaux: [codePostal]
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Some very large cities (like Paris) have A LOT of associated postal codes.
|
|
||||||
// As we generated one result per postal code, we now have a lot of results
|
|
||||||
// for the same city. If the number of results is above the threshold, we use
|
|
||||||
// local search to narrow the results.
|
|
||||||
const limit = searchResultsLimit(term);
|
|
||||||
if (expandedResults.length > limit) {
|
|
||||||
return matchSorter(expandedResults, term, {
|
|
||||||
keys: [(item) => `${item.nom} (${item.codesPostaux[0]})`, 'code'],
|
|
||||||
sorter: (rankedItems) => rankedItems
|
|
||||||
}).slice(0, limit + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expandedResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
const placeholderDepartements = [
|
|
||||||
['63 – Puy-de-Dôme', 'Clermont-Ferrand'],
|
|
||||||
['77 – Seine-et-Marne', 'Melun'],
|
|
||||||
['22 – Côtes d’Armor', 'Saint-Brieuc'],
|
|
||||||
['47 – Lot-et-Garonne', 'Agen']
|
|
||||||
] as const;
|
|
||||||
const [placeholderDepartement, placeholderCommune] =
|
|
||||||
placeholderDepartements[
|
|
||||||
Math.floor(Math.random() * (placeholderDepartements.length - 1))
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function ComboCommunesSearch({
|
|
||||||
id,
|
|
||||||
classNameDepartement,
|
|
||||||
...props
|
|
||||||
}: ComboSearchProps<CommuneResult> & {
|
|
||||||
id: string;
|
|
||||||
classNameDepartement?: string;
|
|
||||||
}) {
|
|
||||||
const group = groupId(id);
|
|
||||||
const [departementValue, setDepartementValue] = useHiddenField(
|
|
||||||
group,
|
|
||||||
'departement'
|
|
||||||
);
|
|
||||||
const [codeDepartement, setCodeDepartement] = useHiddenField(
|
|
||||||
group,
|
|
||||||
'code_departement'
|
|
||||||
);
|
|
||||||
const departementDescribedBy = `${id}_departement_notice`;
|
|
||||||
const communeDescribedBy = `${id}_commune_notice`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueryClientProvider client={queryClient}>
|
|
||||||
<div>
|
|
||||||
<div className="notice" id={departementDescribedBy}>
|
|
||||||
<p>
|
|
||||||
Choisissez le département dans lequel se situe la commune. Vous
|
|
||||||
pouvez entrer le nom ou le code.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ComboDepartementsSearch
|
|
||||||
{...props}
|
|
||||||
id={!codeDepartement ? id : undefined}
|
|
||||||
describedby={departementDescribedBy}
|
|
||||||
placeholder={placeholderDepartement}
|
|
||||||
addForeignDepartement={false}
|
|
||||||
value={departementValue}
|
|
||||||
className={classNameDepartement}
|
|
||||||
onChange={(_, result) => {
|
|
||||||
setDepartementValue(result?.nom ?? '');
|
|
||||||
setCodeDepartement(result?.code ?? '');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{codeDepartement ? (
|
|
||||||
<div>
|
|
||||||
<div className="notice" id={communeDescribedBy}>
|
|
||||||
<p>
|
|
||||||
Choisissez la commune. Vous pouvez entrer le nom ou le code
|
|
||||||
postal.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ComboSearch
|
|
||||||
{...props}
|
|
||||||
id={id}
|
|
||||||
describedby={communeDescribedBy}
|
|
||||||
placeholder={placeholderCommune}
|
|
||||||
scope="communes"
|
|
||||||
scopeExtra={codeDepartement}
|
|
||||||
minimumInputLength={2}
|
|
||||||
transformResult={({ code, nom, codesPostaux }) => [
|
|
||||||
code,
|
|
||||||
`${nom} (${codesPostaux[0]})`
|
|
||||||
]}
|
|
||||||
transformResults={expandResultsWithMultiplePostalCodes}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</QueryClientProvider>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { matchSorter } from 'match-sorter';
|
|
||||||
|
|
||||||
import ComboSearch, { ComboSearchProps } from './ComboSearch';
|
|
||||||
|
|
||||||
type DepartementResult = { code: string; nom: string };
|
|
||||||
|
|
||||||
const extraTerms = [{ code: '99', nom: 'Etranger' }];
|
|
||||||
|
|
||||||
function expandResultsWithForeignDepartement(term: string, result: unknown) {
|
|
||||||
const results = result as DepartementResult[];
|
|
||||||
return [
|
|
||||||
...results,
|
|
||||||
...matchSorter(extraTerms, term, {
|
|
||||||
keys: ['nom', 'code']
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
type ComboDepartementsSearchProps = Omit<
|
|
||||||
ComboSearchProps<DepartementResult> & {
|
|
||||||
addForeignDepartement: boolean;
|
|
||||||
},
|
|
||||||
'transformResult' | 'transformResults'
|
|
||||||
>;
|
|
||||||
|
|
||||||
export function ComboDepartementsSearch({
|
|
||||||
addForeignDepartement = true,
|
|
||||||
...props
|
|
||||||
}: ComboDepartementsSearchProps) {
|
|
||||||
return (
|
|
||||||
<ComboSearch
|
|
||||||
{...props}
|
|
||||||
scope="departements"
|
|
||||||
minimumInputLength={1}
|
|
||||||
transformResult={({ code, nom }) => [code, `${code} - ${nom}`]}
|
|
||||||
transformResults={
|
|
||||||
addForeignDepartement ? expandResultsWithForeignDepartement : undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,22 +1,11 @@
|
||||||
import { QueryClient, QueryFunction } from 'react-query';
|
import { QueryClient, QueryFunction } from 'react-query';
|
||||||
import { httpRequest, isNumeric, getConfig } from '@utils';
|
import { httpRequest, getConfig } from '@utils';
|
||||||
import { matchSorter } from 'match-sorter';
|
|
||||||
|
|
||||||
const API_EDUCATION_QUERY_LIMIT = 5;
|
const API_EDUCATION_QUERY_LIMIT = 5;
|
||||||
const API_GEO_QUERY_LIMIT = 5;
|
|
||||||
const API_ADRESSE_QUERY_LIMIT = 5;
|
const API_ADRESSE_QUERY_LIMIT = 5;
|
||||||
|
|
||||||
// When searching for short strings like "mer", le exact match shows up quite far in
|
|
||||||
// the ordering (~50).
|
|
||||||
//
|
|
||||||
// That's why we deliberately fetch a lot of results, and then let the local matching
|
|
||||||
// (match-sorter) do the work.
|
|
||||||
//
|
|
||||||
// NB: 60 is arbitrary, we may add more if needed.
|
|
||||||
const API_GEO_COMMUNES_QUERY_LIMIT = 60;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
autocomplete: { api_geo_url, api_adresse_url, api_education_url }
|
autocomplete: { api_adresse_url, api_education_url }
|
||||||
} = getConfig();
|
} = getConfig();
|
||||||
|
|
||||||
type QueryKey = readonly [
|
type QueryKey = readonly [
|
||||||
|
@ -25,10 +14,10 @@ type QueryKey = readonly [
|
||||||
extra: string | undefined
|
extra: string | undefined
|
||||||
];
|
];
|
||||||
|
|
||||||
function buildURL(scope: string, term: string, extra?: string) {
|
function buildURL(scope: string, term: string) {
|
||||||
term = term.replace(/\(|\)/g, '');
|
term = term.replace(/\(|\)/g, '');
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
let path = `${api_geo_url}/${scope}`;
|
let path = '';
|
||||||
|
|
||||||
if (scope == 'adresse') {
|
if (scope == 'adresse') {
|
||||||
path = `${api_adresse_url}/search`;
|
path = `${api_adresse_url}/search`;
|
||||||
|
@ -39,40 +28,15 @@ function buildURL(scope: string, term: string, extra?: string) {
|
||||||
params.set('q', term);
|
params.set('q', term);
|
||||||
params.set('rows', `${API_EDUCATION_QUERY_LIMIT}`);
|
params.set('rows', `${API_EDUCATION_QUERY_LIMIT}`);
|
||||||
params.set('dataset', 'fr-en-annuaire-education');
|
params.set('dataset', 'fr-en-annuaire-education');
|
||||||
} else if (scope == 'communes') {
|
|
||||||
if (extra) {
|
|
||||||
params.set('codeDepartement', extra);
|
|
||||||
}
|
|
||||||
if (isNumeric(term)) {
|
|
||||||
params.set('codePostal', term);
|
|
||||||
} else {
|
|
||||||
params.set('nom', term);
|
|
||||||
params.set('boost', 'population');
|
|
||||||
}
|
|
||||||
params.set('limit', `${API_GEO_COMMUNES_QUERY_LIMIT}`);
|
|
||||||
} else {
|
|
||||||
if (isNumeric(term)) {
|
|
||||||
params.set('code', term.padStart(2, '0'));
|
|
||||||
} else {
|
|
||||||
params.set('nom', term);
|
|
||||||
}
|
|
||||||
if (scope == 'departements') {
|
|
||||||
params.set('zone', 'metro,drom,com');
|
|
||||||
}
|
|
||||||
params.set('limit', `${API_GEO_QUERY_LIMIT}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${path}?${params}`;
|
return `${path}?${params}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultQueryFn: QueryFunction<unknown, QueryKey> = async ({
|
const defaultQueryFn: QueryFunction<unknown, QueryKey> = async ({
|
||||||
queryKey: [scope, term, extra],
|
queryKey: [scope, term],
|
||||||
signal
|
signal
|
||||||
}) => {
|
}) => {
|
||||||
if (scope == 'pays') {
|
|
||||||
return matchSorter(await getPays(signal), term, { keys: ['label'] });
|
|
||||||
}
|
|
||||||
|
|
||||||
// BAN will error with queries less then 3 chars long
|
// BAN will error with queries less then 3 chars long
|
||||||
if (scope == 'adresse' && term.length < 3) {
|
if (scope == 'adresse' && term.length < 3) {
|
||||||
return {
|
return {
|
||||||
|
@ -83,23 +47,10 @@ const defaultQueryFn: QueryFunction<unknown, QueryKey> = async ({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = buildURL(scope, term, extra);
|
const url = buildURL(scope, term);
|
||||||
return httpRequest(url, { csrf: false, signal }).json();
|
return httpRequest(url, { csrf: false, signal }).json();
|
||||||
};
|
};
|
||||||
|
|
||||||
let paysCache: { label: string }[];
|
|
||||||
async function getPays(signal?: AbortSignal): Promise<{ label: string }[]> {
|
|
||||||
if (!paysCache) {
|
|
||||||
const data = await httpRequest('/api/pays', { signal }).json<
|
|
||||||
typeof paysCache
|
|
||||||
>();
|
|
||||||
if (data) {
|
|
||||||
paysCache = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paysCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const queryClient = new QueryClient({
|
export const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
|
|
|
@ -21,30 +21,110 @@
|
||||||
# type_de_champ_id :integer
|
# type_de_champ_id :integer
|
||||||
#
|
#
|
||||||
class Champs::CommuneChamp < Champs::TextChamp
|
class Champs::CommuneChamp < Champs::TextChamp
|
||||||
store_accessor :value_json, :departement, :code_departement
|
store_accessor :value_json, :code_departement, :code_postal
|
||||||
|
before_validation :on_code_postal_change
|
||||||
|
|
||||||
def for_export
|
def for_export
|
||||||
[value, external_id, departement? ? departement_code_and_name : '']
|
[name, code, departement? ? departement_code_and_name : '']
|
||||||
end
|
end
|
||||||
|
|
||||||
def name_departement
|
def departement_name
|
||||||
# FIXME we originaly saved already formatted departement with the code in the name
|
APIGeoService.departement_name(code_departement)
|
||||||
departement&.gsub(/^(.[0-9])\s-\s/, '')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def departement_code_and_name
|
def departement_code_and_name
|
||||||
"#{code_departement} - #{name_departement}"
|
"#{code_departement} – #{departement_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def departement
|
||||||
|
{ code: code_departement, name: departement_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
def departement?
|
def departement?
|
||||||
departement.present?
|
code_departement.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def code?
|
def code?
|
||||||
code.present?
|
code.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def code_postal?
|
||||||
|
code_postal.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
if code?
|
||||||
|
"#{APIGeoService.commune_name(code_departement, code)} (#{code_postal_with_fallback})"
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
name
|
||||||
|
end
|
||||||
|
|
||||||
def code
|
def code
|
||||||
external_id
|
external_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def selected
|
||||||
|
code
|
||||||
|
end
|
||||||
|
|
||||||
|
def communes
|
||||||
|
if code_postal_with_fallback?
|
||||||
|
APIGeoService.communes_by_postal_code(code_postal_with_fallback)
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def value=(code)
|
||||||
|
if code.blank? || !code_postal_with_fallback?
|
||||||
|
self.code_departement = nil
|
||||||
|
self.external_id = nil
|
||||||
|
super(nil)
|
||||||
|
else
|
||||||
|
commune = communes.find { _1[:code] == code }
|
||||||
|
if commune.present?
|
||||||
|
self.code_departement = commune[:departement_code]
|
||||||
|
self.external_id = commune[:code]
|
||||||
|
super(commune[:name])
|
||||||
|
else
|
||||||
|
self.code_departement = nil
|
||||||
|
self.external_id = nil
|
||||||
|
super(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def code_postal_with_fallback?
|
||||||
|
code_postal_with_fallback.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
# We try to extract the postal code from the value, which is the name of the commune and the
|
||||||
|
# postal code in brackets. This is temporary until we do a full data migration.
|
||||||
|
def code_postal_with_fallback
|
||||||
|
if code_postal?
|
||||||
|
code_postal
|
||||||
|
elsif value.present?
|
||||||
|
match = value.match(/[^(]\(([^\)]*)\)$/)
|
||||||
|
match[1] if match.present?
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def on_code_postal_change
|
||||||
|
if code_postal_changed?
|
||||||
|
if communes.one?
|
||||||
|
self.value = communes.first[:code]
|
||||||
|
else
|
||||||
|
self.value = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -514,7 +514,7 @@ class TypeDeChamp < ApplicationRecord
|
||||||
|
|
||||||
def self.refresh_after_update?(type_champ)
|
def self.refresh_after_update?(type_champ)
|
||||||
case type_champ
|
case type_champ
|
||||||
when type_champs.fetch(:epci)
|
when type_champs.fetch(:epci), type_champs.fetch(:communes)
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
|
|
@ -1,47 +1,38 @@
|
||||||
class TypesDeChamp::PrefillCommuneTypeDeChamp < TypesDeChamp::PrefillTypeDeChamp
|
class TypesDeChamp::PrefillCommuneTypeDeChamp < TypesDeChamp::PrefillTypeDeChamp
|
||||||
def all_possible_values
|
def all_possible_values
|
||||||
departements.map do |departement|
|
[]
|
||||||
"#{departement[:code]} (#{departement[:name]}) : https://geo.api.gouv.fr/communes?codeDepartement=#{departement[:code]}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def example_value
|
def example_value
|
||||||
departement_code = departements.pick(:code)
|
departement_code = departements.pick(:code)
|
||||||
commune_code = APIGeoService.communes(departement_code).pick(:code)
|
APIGeoService.communes(departement_code).pick(:postal_code, :code)
|
||||||
[departement_code, commune_code]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_assignable_attributes(champ, value)
|
def to_assignable_attributes(champ, value)
|
||||||
return if value.blank? || !value.is_a?(Array)
|
return if value.blank? || !value.is_a?(Array)
|
||||||
return if (departement_code = value.first).blank?
|
return if (postal_code = value.first).blank?
|
||||||
return if (departement_name = APIGeoService.departement_name(departement_code)).blank?
|
return if APIGeoService.communes_by_postal_code(postal_code).empty?
|
||||||
return if !value.one? && (commune_code = value.second).blank?
|
return if !value.one? && (commune_code = value.second).blank?
|
||||||
return if !value.one? && (commune_name = APIGeoService.commune_name(departement_code, commune_code)).blank?
|
return if !value.one? && !APIGeoService.communes_by_postal_code(postal_code).any? { _1[:code] == commune_code }
|
||||||
|
|
||||||
if value.one?
|
if value.one?
|
||||||
departement_attributes(champ, departement_code, departement_name)
|
code_postal_attributes(champ, postal_code)
|
||||||
else
|
else
|
||||||
departement_and_commune_attributes(champ, departement_code, departement_name, commune_code, commune_name)
|
code_postal_and_commune_attributes(champ, postal_code, commune_code)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def departement_attributes(champ, departement_code, departement_name)
|
def code_postal_attributes(champ, postal_code)
|
||||||
{
|
{
|
||||||
id: champ.id,
|
id: champ.id,
|
||||||
code_departement: departement_code,
|
code_postal: postal_code
|
||||||
departement: departement_name
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def departement_and_commune_attributes(champ, departement_code, departement_name, commune_code, commune_name)
|
def code_postal_and_commune_attributes(champ, postal_code, commune_code)
|
||||||
postal_code = APIGeoService.commune_postal_codes(departement_code, commune_code).first
|
code_postal_attributes(champ, postal_code).merge(value: commune_code)
|
||||||
|
|
||||||
departement_attributes(champ, departement_code, departement_name).merge(
|
|
||||||
external_id: commune_code,
|
|
||||||
value: "#{commune_name} (#{postal_code})"
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def departements
|
def departements
|
||||||
|
|
|
@ -47,25 +47,6 @@ class APIGeoService
|
||||||
departements.find { _1[:name] == name }&.dig(:code)
|
departements.find { _1[:name] == name }&.dig(:code)
|
||||||
end
|
end
|
||||||
|
|
||||||
def communes(departement_code)
|
|
||||||
get_from_api_geo(
|
|
||||||
"communes?codeDepartement=#{departement_code}",
|
|
||||||
additional_keys: { postal_codes: :codesPostaux }
|
|
||||||
).sort_by { I18n.transliterate(_1[:name]) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def commune_name(departement_code, code)
|
|
||||||
communes(departement_code).find { _1[:code] == code }&.dig(:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commune_code(departement_code, name)
|
|
||||||
communes(departement_code).find { _1[:name] == name }&.dig(:code)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commune_postal_codes(departement_code, code)
|
|
||||||
communes(departement_code).find { _1[:code] == code }&.dig(:postal_codes)
|
|
||||||
end
|
|
||||||
|
|
||||||
def epcis(departement_code)
|
def epcis(departement_code)
|
||||||
get_from_api_geo("epcis?codeDepartement=#{departement_code}").sort_by { I18n.transliterate(_1[:name]) }
|
get_from_api_geo("epcis?codeDepartement=#{departement_code}").sort_by { I18n.transliterate(_1[:name]) }
|
||||||
end
|
end
|
||||||
|
@ -78,18 +59,55 @@ class APIGeoService
|
||||||
epcis(departement_code).find { _1[:name] == name }&.dig(:code)
|
epcis(departement_code).find { _1[:name] == name }&.dig(:code)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def communes(departement_code)
|
||||||
|
get_from_api_geo("communes?codeDepartement=#{departement_code}&type=commune-actuelle,arrondissement-municipal").sort_by { I18n.transliterate([_1[:name], _1[:postal_code]].join(' ')) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def communes_by_postal_code(postal_code)
|
||||||
|
if postal_code.size > 3
|
||||||
|
metro_code = postal_code[0..1]
|
||||||
|
drom_com_code = postal_code[0..2]
|
||||||
|
if metro_code == '20'
|
||||||
|
communes('2A') + communes('2B')
|
||||||
|
elsif metro_code == '97' || metro_code == '98'
|
||||||
|
departement_name(drom_com_code) ? communes(drom_com_code) : []
|
||||||
|
else
|
||||||
|
departement_name(metro_code) ? communes(metro_code) : []
|
||||||
|
end
|
||||||
|
.filter { _1[:postal_code] == postal_code }
|
||||||
|
.sort_by { I18n.transliterate([_1[:name], _1[:postal_code]].join(' ')) }
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def commune_name(departement_code, code)
|
||||||
|
communes(departement_code).find { _1[:code] == code }&.dig(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commune_code(departement_code, name)
|
||||||
|
communes(departement_code).find { _1[:name] == name }&.dig(:code)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def get_from_api_geo(scope, additional_keys: {})
|
def get_from_api_geo(scope)
|
||||||
Rails.cache.fetch("api_geo_#{scope}", expires_in: 1.year) do
|
Rails.cache.fetch("api_geo_#{scope}", expires_in: 1.year) do
|
||||||
response = Typhoeus.get("#{API_GEO_URL}/#{scope}")
|
response = Typhoeus.get("#{API_GEO_URL}/#{scope}")
|
||||||
JSON.parse(response.body)
|
JSON.parse(response.body).map(&:symbolize_keys).flat_map do |result|
|
||||||
.map(&:symbolize_keys)
|
item = {
|
||||||
.map do |result|
|
name: result[:nom].tr("'", '’'),
|
||||||
data = { name: result[:nom].tr("'", '’'), code: result[:code] }
|
code: result[:code],
|
||||||
additional_keys.each { |key, value| data = data.merge(key => result[value]) }
|
epci_code: result[:codeEpci],
|
||||||
data
|
departement_code: result[:codeDepartement]
|
||||||
|
}.compact
|
||||||
|
|
||||||
|
if result[:codesPostaux].present?
|
||||||
|
result[:codesPostaux].map { item.merge(postal_code: _1) }
|
||||||
|
else
|
||||||
|
[item]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
= format_text_value(champ.to_s)
|
= champ.name
|
||||||
- if champ.code?
|
- if champ.code?
|
||||||
%p.text-sm
|
%p.text-sm
|
||||||
Code INSEE :
|
Code INSEE :
|
||||||
|
|
46
spec/fixtures/cassettes/api_geo_all.yml
vendored
46
spec/fixtures/cassettes/api_geo_all.yml
vendored
File diff suppressed because one or more lines are too long
329
spec/fixtures/cassettes/api_geo_communes.yml
vendored
329
spec/fixtures/cassettes/api_geo_communes.yml
vendored
File diff suppressed because one or more lines are too long
79
spec/fixtures/cassettes/graphql_communes.yml
vendored
Normal file
79
spec/fixtures/cassettes/graphql_communes.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -26,7 +26,7 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'dossier with champs' do
|
describe 'dossier with champs', vcr: { cassette_name: 'graphql_communes' } do
|
||||||
let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :communes }, { type: :address }, { type: :siret }]) }
|
let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :communes }, { type: :address }, { type: :siret }]) }
|
||||||
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
|
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
|
||||||
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
|
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
|
||||||
|
|
|
@ -1,19 +1,43 @@
|
||||||
describe Champs::CommuneChamp do
|
describe Champs::CommuneChamp do
|
||||||
let(:type_de_champ) { create(:type_de_champ_communes, libelle: 'Ma commune') }
|
let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) }
|
||||||
let(:champ) { Champs::CommuneChamp.new(value: value, external_id: code_insee, departement: departement, code_departement: code_departement, type_de_champ: type_de_champ) }
|
|
||||||
let(:value) { 'Châteldon (63290)' }
|
before do
|
||||||
|
allow(Rails).to receive(:cache).and_return(memory_store)
|
||||||
|
Rails.cache.clear
|
||||||
|
end
|
||||||
|
|
||||||
let(:code_insee) { '63102' }
|
let(:code_insee) { '63102' }
|
||||||
let(:departement) { '' }
|
let(:code_postal) { '63290' }
|
||||||
let(:code_departement) { '' }
|
let(:code_departement) { '63' }
|
||||||
|
|
||||||
it { expect(champ.value).to eq('Châteldon (63290)') }
|
describe 'value', vcr: { cassette_name: 'api_geo_communes' } do
|
||||||
it { expect(champ.external_id).to eq('63102') }
|
let(:champ) { create(:champ_communes, code_postal: code_postal) }
|
||||||
it { expect(champ.for_export).to eq(['Châteldon (63290)', '63102', '']) }
|
|
||||||
|
|
||||||
context do
|
it 'with code_postal' do
|
||||||
let(:departement) { 'Puy-de-Dôme' }
|
champ.update(value: code_insee)
|
||||||
let(:code_departement) { '63' }
|
expect(champ.name).to eq('Châteldon (63290)')
|
||||||
|
expect(champ.external_id).to eq(code_insee)
|
||||||
|
expect(champ.code).to eq(code_insee)
|
||||||
|
expect(champ.code_departement).to eq(code_departement)
|
||||||
|
expect(champ.code_postal).to eq(code_postal)
|
||||||
|
expect(champ.for_export).to eq(['Châteldon (63290)', '63102', '63 – Puy-de-Dôme'])
|
||||||
|
expect(champ.communes.size).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
it { expect(champ.for_export).to eq(['Châteldon (63290)', '63102', '63 - Puy-de-Dôme']) }
|
context 'when code_postal is nil', vcr: { cassette_name: 'api_geo_communes' } do
|
||||||
|
let(:champ) { create(:champ_communes, external_id: code_insee, code_departement:) }
|
||||||
|
|
||||||
|
it 'with value' do
|
||||||
|
champ.update_column(:value, 'Châteldon (63290)')
|
||||||
|
expect(champ.name).to eq('Châteldon (63290)')
|
||||||
|
expect(champ.external_id).to eq(code_insee)
|
||||||
|
expect(champ.code).to eq(code_insee)
|
||||||
|
expect(champ.code_departement).to eq(code_departement)
|
||||||
|
expect(champ.code_postal).to be_nil
|
||||||
|
expect(champ.code_postal_with_fallback).to eq(code_postal)
|
||||||
|
expect(champ.for_export).to eq(['Châteldon (63290)', '63102', '63 – Puy-de-Dôme'])
|
||||||
|
expect(champ.communes.size).to eq(8)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1573,7 +1573,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "champs_for_export" do
|
describe "champs_for_export", vcr: { cassette_name: 'api_geo_communes' } do
|
||||||
context 'with a unconditionnal procedure' do
|
context 'with a unconditionnal procedure' do
|
||||||
let(:procedure) { create(:procedure, :with_type_de_champ, :with_datetime, :with_yes_no, :with_explication, :with_commune, :with_repetition, zones: [create(:zone)]) }
|
let(:procedure) { create(:procedure, :with_type_de_champ, :with_datetime, :with_yes_no, :with_explication, :with_commune, :with_repetition, zones: [create(:zone)]) }
|
||||||
let(:text_type_de_champ) { procedure.active_revision.types_de_champ_public.find { |type_de_champ| type_de_champ.type_champ == TypeDeChamp.type_champs.fetch(:text) } }
|
let(:text_type_de_champ) { procedure.active_revision.types_de_champ_public.find { |type_de_champ| type_de_champ.type_champ == TypeDeChamp.type_champs.fetch(:text) } }
|
||||||
|
|
|
@ -139,7 +139,7 @@ RSpec.describe PrefillParams do
|
||||||
it_behaves_like "a champ public value that is authorized", :checkbox, "false"
|
it_behaves_like "a champ public value that is authorized", :checkbox, "false"
|
||||||
it_behaves_like "a champ public value that is authorized", :drop_down_list, "value"
|
it_behaves_like "a champ public value that is authorized", :drop_down_list, "value"
|
||||||
it_behaves_like "a champ public value that is authorized", :departements, "03"
|
it_behaves_like "a champ public value that is authorized", :departements, "03"
|
||||||
it_behaves_like "a champ public value that is authorized", :communes, ['01', '01457']
|
it_behaves_like "a champ public value that is authorized", :communes, ['01540', '01457']
|
||||||
it_behaves_like "a champ public value that is authorized", :address, "20 avenue de Ségur 75007 Paris"
|
it_behaves_like "a champ public value that is authorized", :address, "20 avenue de Ségur 75007 Paris"
|
||||||
it_behaves_like "a champ public value that is authorized", :annuaire_education, "0050009H"
|
it_behaves_like "a champ public value that is authorized", :annuaire_education, "0050009H"
|
||||||
it_behaves_like "a champ public value that is authorized", :multiple_drop_down_list, ["val1", "val2"]
|
it_behaves_like "a champ public value that is authorized", :multiple_drop_down_list, ["val1", "val2"]
|
||||||
|
@ -183,7 +183,7 @@ RSpec.describe PrefillParams do
|
||||||
it_behaves_like "a champ private value that is authorized", :rna, "value"
|
it_behaves_like "a champ private value that is authorized", :rna, "value"
|
||||||
it_behaves_like "a champ private value that is authorized", :siret, "13002526500013"
|
it_behaves_like "a champ private value that is authorized", :siret, "13002526500013"
|
||||||
it_behaves_like "a champ private value that is authorized", :departements, "03"
|
it_behaves_like "a champ private value that is authorized", :departements, "03"
|
||||||
it_behaves_like "a champ private value that is authorized", :communes, ['01', '01457']
|
it_behaves_like "a champ private value that is authorized", :communes, ['01540', '01457']
|
||||||
it_behaves_like "a champ private value that is authorized", :address, "20 avenue de Ségur 75007 Paris"
|
it_behaves_like "a champ private value that is authorized", :address, "20 avenue de Ségur 75007 Paris"
|
||||||
it_behaves_like "a champ private value that is authorized", :annuaire_education, "0050009H"
|
it_behaves_like "a champ private value that is authorized", :annuaire_education, "0050009H"
|
||||||
it_behaves_like "a champ private value that is authorized", :multiple_drop_down_list, ["val1", "val2"]
|
it_behaves_like "a champ private value that is authorized", :multiple_drop_down_list, ["val1", "val2"]
|
||||||
|
|
|
@ -26,21 +26,21 @@ RSpec.describe TypesDeChamp::PrefillCommuneTypeDeChamp do
|
||||||
it { is_expected.to be_kind_of(TypesDeChamp::PrefillTypeDeChamp) }
|
it { is_expected.to be_kind_of(TypesDeChamp::PrefillTypeDeChamp) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#all_possible_values' do
|
# describe '#all_possible_values' do
|
||||||
let(:expected_values) do
|
# let(:expected_values) do
|
||||||
departements.map { |departement| "#{departement[:code]} (#{departement[:name]}) : https://geo.api.gouv.fr/communes?codeDepartement=#{departement[:code]}" }
|
# departements.map { |departement| "#{departement[:code]} (#{departement[:name]}) : https://geo.api.gouv.fr/communes?codeDepartement=#{departement[:code]}" }
|
||||||
end
|
# end
|
||||||
subject(:all_possible_values) { described_class.new(type_de_champ, procedure.active_revision).all_possible_values }
|
# subject(:all_possible_values) { described_class.new(type_de_champ, procedure.active_revision).all_possible_values }
|
||||||
|
|
||||||
it { expect(all_possible_values).to match(expected_values) }
|
# it { expect(all_possible_values).to match(expected_values) }
|
||||||
end
|
# end
|
||||||
|
|
||||||
describe '#example_value' do
|
describe '#example_value' do
|
||||||
let(:departement_code) { departements.pick(:code) }
|
let(:departement_code) { departements.pick(:code) }
|
||||||
let(:commune_code) { APIGeoService.communes(departement_code).pick(:code) }
|
let(:value) { APIGeoService.communes(departement_code).pick(:postal_code, :code) }
|
||||||
subject(:example_value) { described_class.new(type_de_champ, procedure.active_revision).example_value }
|
subject(:example_value) { described_class.new(type_de_champ, procedure.active_revision).example_value }
|
||||||
|
|
||||||
it { is_expected.to eq([departement_code, commune_code]) }
|
it { is_expected.to eq(value) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#to_assignable_attributes' do
|
describe '#to_assignable_attributes' do
|
||||||
|
@ -65,22 +65,22 @@ RSpec.describe TypesDeChamp::PrefillCommuneTypeDeChamp do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is an array of one element' do
|
context 'when the value is an array of one element' do
|
||||||
context 'when the first element is a valid departement code' do
|
context 'when the first element is a valid postal code' do
|
||||||
let(:value) { ['01'] }
|
let(:value) { ['01540'] }
|
||||||
it { is_expected.to match({ id: champ.id, code_departement: '01', departement: 'Ain' }) }
|
it { is_expected.to match({ id: champ.id, code_postal: '01540' }) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the first element is not a valid departement code' do
|
context 'when the first element is not a valid postal code' do
|
||||||
let(:value) { ['totoro'] }
|
let(:value) { ['totoro'] }
|
||||||
it { is_expected.to match(nil) }
|
it { is_expected.to match(nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is an array of two elements' do
|
context 'when the value is an array of two elements' do
|
||||||
context 'when the first element is a valid departement code' do
|
context 'when the first element is a valid postal code' do
|
||||||
context 'when the second element is a valid insee code' do
|
context 'when the second element is a valid insee code' do
|
||||||
let(:value) { ['01', '01457'] }
|
let(:value) { ['01540', '01457'] }
|
||||||
it { is_expected.to match({ id: champ.id, code_departement: '01', departement: 'Ain', external_id: '01457', value: 'Vonnas (01540)' }) }
|
it { is_expected.to match({ id: champ.id, code_postal: '01540', value: '01457' }) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the second element is not a valid insee code' do
|
context 'when the second element is not a valid insee code' do
|
||||||
|
@ -89,26 +89,26 @@ RSpec.describe TypesDeChamp::PrefillCommuneTypeDeChamp do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the first element is not a valid departement code' do
|
context 'when the first element is not a valid postal code' do
|
||||||
let(:value) { ['totoro', '01457'] }
|
let(:value) { ['totoro', '01457'] }
|
||||||
it { is_expected.to match(nil) }
|
it { is_expected.to match(nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is an array of three or more elements' do
|
context 'when the value is an array of three or more elements' do
|
||||||
context 'when the first element is a valid departement code' do
|
context 'when the first element is a valid postal code' do
|
||||||
context 'when the second element is a valid insee code' do
|
context 'when the second element is a valid insee code' do
|
||||||
let(:value) { ['01', '01457', 'hello'] }
|
let(:value) { ['01540', '01457', 'hello'] }
|
||||||
it { is_expected.to match({ id: champ.id, code_departement: '01', departement: 'Ain', external_id: '01457', value: 'Vonnas (01540)' }) }
|
it { is_expected.to match({ id: champ.id, code_postal: '01540', value: '01457' }) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the second element is not a valid insee code' do
|
context 'when the second element is not a valid insee code' do
|
||||||
let(:value) { ['01', 'totoro', 'hello'] }
|
let(:value) { ['01540', 'totoro', 'hello'] }
|
||||||
it { is_expected.to match(nil) }
|
it { is_expected.to match(nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the first element is not a valid departement code' do
|
context 'when the first element is not a valid postal code' do
|
||||||
let(:value) { ['totoro', '01457', 'hello'] }
|
let(:value) { ['totoro', '01457', 'hello'] }
|
||||||
it { is_expected.to match(nil) }
|
it { is_expected.to match(nil) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,9 +45,19 @@ describe APIGeoService do
|
||||||
|
|
||||||
describe 'communes', vcr: { cassette_name: 'api_geo_communes' } do
|
describe 'communes', vcr: { cassette_name: 'api_geo_communes' } do
|
||||||
it 'return sorted results' do
|
it 'return sorted results' do
|
||||||
expect(APIGeoService.communes('01').size).to eq(393)
|
expect(APIGeoService.communes('01').size).to eq(399)
|
||||||
expect(APIGeoService.communes('01').first).to eq(code: '01004', name: 'Ambérieu-en-Bugey', postal_codes: ['01500'])
|
expect(APIGeoService.communes('01').first).to eq(code: '01004', name: 'Ambérieu-en-Bugey', postal_code: '01500', departement_code: '01', epci_code: '240100883')
|
||||||
expect(APIGeoService.communes('01').last).to eq(code: '01457', name: 'Vonnas', postal_codes: ['01540'])
|
expect(APIGeoService.communes('01').last).to eq(code: '01457', name: 'Vonnas', postal_code: '01540', departement_code: '01', epci_code: '200070555')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'communes_by_postal_code', vcr: { cassette_name: 'api_geo_communes' } do
|
||||||
|
it 'return results' do
|
||||||
|
expect(APIGeoService.communes_by_postal_code('75019').size).to eq(2)
|
||||||
|
expect(APIGeoService.communes_by_postal_code('69005').size).to eq(2)
|
||||||
|
expect(APIGeoService.communes_by_postal_code('13006').size).to eq(2)
|
||||||
|
expect(APIGeoService.communes_by_postal_code('73480').size).to eq(3)
|
||||||
|
expect(APIGeoService.communes_by_postal_code('20000').first[:code]).to eq('2A004')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,11 +71,6 @@ describe APIGeoService do
|
||||||
it { is_expected.to eq('01457') }
|
it { is_expected.to eq('01457') }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'commune_postal_codes', vcr: { cassette_name: 'api_geo_communes' } do
|
|
||||||
subject { APIGeoService.commune_postal_codes('01', '01457') }
|
|
||||||
it { is_expected.to eq(['01540']) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'epcis', vcr: { cassette_name: 'api_geo_epcis' } do
|
describe 'epcis', vcr: { cassette_name: 'api_geo_epcis' } do
|
||||||
it 'return sorted results' do
|
it 'return sorted results' do
|
||||||
expect(APIGeoService.epcis('01').size).to eq(17)
|
expect(APIGeoService.epcis('01').size).to eq(17)
|
||||||
|
|
|
@ -25,7 +25,7 @@ shared_examples "the user has got a prefilled dossier, owned by themselves" do
|
||||||
expect(page).to have_content(multiple_drop_down_list_values.last)
|
expect(page).to have_content(multiple_drop_down_list_values.last)
|
||||||
expect(page).to have_field(type_de_champ_epci.libelle, with: epci_value.last)
|
expect(page).to have_field(type_de_champ_epci.libelle, with: epci_value.last)
|
||||||
expect(page).to have_field(type_de_champ_dossier_link.libelle, with: dossier_link_value)
|
expect(page).to have_field(type_de_champ_dossier_link.libelle, with: dossier_link_value)
|
||||||
expect(page).to have_selector("input[value='Vonnas (01540)']")
|
expect(page).to have_field(commune_libelle, with: '01457')
|
||||||
expect(page).to have_content(annuaire_education_value.last)
|
expect(page).to have_content(annuaire_education_value.last)
|
||||||
expect(page).to have_content(address_value.last)
|
expect(page).to have_content(address_value.last)
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,8 +44,8 @@ describe 'The user' do
|
||||||
select('Australie', from: form_id_for('pays'))
|
select('Australie', from: form_id_for('pays'))
|
||||||
select('Martinique', from: form_id_for('regions'))
|
select('Martinique', from: form_id_for('regions'))
|
||||||
select('02 – Aisne', from: form_id_for('departements'))
|
select('02 – Aisne', from: form_id_for('departements'))
|
||||||
select_combobox('communes', 'Ai', '02 - Aisne', check: false)
|
fill_in('Code postal de la commune', with: '60400')
|
||||||
select_combobox('communes', 'Ambl', 'Ambléon (01300)')
|
select('Brétigny (60400)', from: form_id_for('communes'))
|
||||||
|
|
||||||
fill_in('dossier_link', with: '123')
|
fill_in('dossier_link', with: '123')
|
||||||
find('.editable-champ-piece_justificative input[type=file]').attach_file(Rails.root + 'spec/fixtures/files/file.pdf')
|
find('.editable-champ-piece_justificative input[type=file]').attach_file(Rails.root + 'spec/fixtures/files/file.pdf')
|
||||||
|
@ -74,7 +74,7 @@ describe 'The user' do
|
||||||
expect(champ_value_for('pays')).to eq('Australie')
|
expect(champ_value_for('pays')).to eq('Australie')
|
||||||
expect(champ_value_for('regions')).to eq('Martinique')
|
expect(champ_value_for('regions')).to eq('Martinique')
|
||||||
expect(champ_value_for('departements')).to eq('Aisne')
|
expect(champ_value_for('departements')).to eq('Aisne')
|
||||||
expect(champ_value_for('communes')).to eq('Ambléon (01300)')
|
expect(champ_value_for('communes')).to eq('Brétigny')
|
||||||
expect(champ_value_for('dossier_link')).to eq('123')
|
expect(champ_value_for('dossier_link')).to eq('123')
|
||||||
expect(champ_value_for('piece_justificative')).to be_nil # antivirus hasn't approved the file yet
|
expect(champ_value_for('piece_justificative')).to be_nil # antivirus hasn't approved the file yet
|
||||||
|
|
||||||
|
@ -98,7 +98,8 @@ describe 'The user' do
|
||||||
expect(page).to have_selected_value('regions', selected: 'Martinique')
|
expect(page).to have_selected_value('regions', selected: 'Martinique')
|
||||||
expect(page).to have_selected_value('departements', selected: '02 – Aisne')
|
expect(page).to have_selected_value('departements', selected: '02 – Aisne')
|
||||||
check_selected_value('multiple_choice_drop_down_list_long', with: ['alpha', 'charly'])
|
check_selected_value('multiple_choice_drop_down_list_long', with: ['alpha', 'charly'])
|
||||||
check_selected_value('communes', with: 'Ambléon (01300)')
|
expect(page).to have_selected_value('communes', selected: 'Brétigny (60400)')
|
||||||
|
expect(page).to have_selected_value('pays', selected: 'Australie')
|
||||||
expect(page).to have_field('dossier_link', with: '123')
|
expect(page).to have_field('dossier_link', with: '123')
|
||||||
expect(page).to have_text('file.pdf')
|
expect(page).to have_text('file.pdf')
|
||||||
expect(page).to have_text('Analyse antivirus en cours')
|
expect(page).to have_text('Analyse antivirus en cours')
|
||||||
|
|
|
@ -32,7 +32,8 @@ describe 'Prefilling a dossier (with a GET request):', js: true do
|
||||||
}
|
}
|
||||||
let(:epci_value) { ['01', '200029999'] }
|
let(:epci_value) { ['01', '200029999'] }
|
||||||
let(:dossier_link_value) { '42' }
|
let(:dossier_link_value) { '42' }
|
||||||
let(:commune_value) { ['01', '01457'] } # Vonnas (01540)
|
let(:commune_value) { ['01540', '01457'] } # Vonnas (01540)
|
||||||
|
let(:commune_libelle) { 'Vonnas (01540)' }
|
||||||
let(:address_value) { "20 Avenue de Ségur 75007 Paris" }
|
let(:address_value) { "20 Avenue de Ségur 75007 Paris" }
|
||||||
let(:sub_type_de_champs_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) }
|
let(:sub_type_de_champs_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) }
|
||||||
let(:text_repetition_libelle) { sub_type_de_champs_repetition.first.libelle }
|
let(:text_repetition_libelle) { sub_type_de_champs_repetition.first.libelle }
|
||||||
|
|
|
@ -31,7 +31,8 @@ describe 'Prefilling a dossier (with a POST request):', js: true do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
let(:epci_value) { ['01', '200029999'] }
|
let(:epci_value) { ['01', '200029999'] }
|
||||||
let(:commune_value) { ['01', '01457'] } # Vonnas (01540)
|
let(:commune_value) { ['01540', '01457'] } # Vonnas (01540)
|
||||||
|
let(:commune_libelle) { 'Vonnas (01540)' }
|
||||||
let(:address_value) { "20 Avenue de Ségur 75007 Paris" }
|
let(:address_value) { "20 Avenue de Ségur 75007 Paris" }
|
||||||
let(:sub_type_de_champs_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) }
|
let(:sub_type_de_champs_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) }
|
||||||
let(:text_repetition_libelle) { sub_type_de_champs_repetition.first.libelle }
|
let(:text_repetition_libelle) { sub_type_de_champs_repetition.first.libelle }
|
||||||
|
|
Loading…
Add table
Reference in a new issue