diff --git a/app/models/champs/departement_champ.rb b/app/models/champs/departement_champ.rb index 13edb4bb4..5a99ce8ad 100644 --- a/app/models/champs/departement_champ.rb +++ b/app/models/champs/departement_champ.rb @@ -21,6 +21,9 @@ # type_de_champ_id :integer # class Champs::DepartementChamp < Champs::TextChamp + validate :value_in_departement_names, unless: -> { value.nil? } + validate :external_id_in_departement_codes, unless: -> { external_id.nil? } + def for_export [name, code] end @@ -65,6 +68,9 @@ class Champs::DepartementChamp < Champs::TextChamp elsif code.blank? self.external_id = nil super(nil) + else + self.external_id = APIGeoService.departement_code(code) + super(code) end end @@ -73,4 +79,16 @@ class Champs::DepartementChamp < Champs::TextChamp def formatted_value blank? ? "" : "#{code} – #{name}" end + + def value_in_departement_names + return if value.in?(APIGeoService.departements.pluck(:name)) + + errors.add(:value, :not_in_departement_names) + end + + def external_id_in_departement_codes + return if external_id.in?(APIGeoService.departements.pluck(:code)) + + errors.add(:external_id, :not_in_departement_codes) + end end diff --git a/app/models/prefill_params.rb b/app/models/prefill_params.rb index e4ded1975..33261a8ac 100644 --- a/app/models/prefill_params.rb +++ b/app/models/prefill_params.rb @@ -40,7 +40,8 @@ class PrefillParams TypeDeChamp.type_champs.fetch(:yes_no), TypeDeChamp.type_champs.fetch(:checkbox), TypeDeChamp.type_champs.fetch(:pays), - TypeDeChamp.type_champs.fetch(:regions) + TypeDeChamp.type_champs.fetch(:regions), + TypeDeChamp.type_champs.fetch(:departements) ] attr_reader :champ, :value diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index afa6a821a..05091ec70 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -267,7 +267,8 @@ class TypeDeChamp < ApplicationRecord TypeDeChamp.type_champs.fetch(:yes_no), TypeDeChamp.type_champs.fetch(:checkbox), TypeDeChamp.type_champs.fetch(:drop_down_list), - TypeDeChamp.type_champs.fetch(:regions) + TypeDeChamp.type_champs.fetch(:regions), + TypeDeChamp.type_champs.fetch(:departements) ]) end diff --git a/app/models/types_de_champ/prefill_departement_type_de_champ.rb b/app/models/types_de_champ/prefill_departement_type_de_champ.rb new file mode 100644 index 000000000..2ec1d1d11 --- /dev/null +++ b/app/models/types_de_champ/prefill_departement_type_de_champ.rb @@ -0,0 +1,11 @@ +class TypesDeChamp::PrefillDepartementTypeDeChamp < TypesDeChamp::PrefillTypeDeChamp + def possible_values + departements.map { |departement| "#{departement[:code]} (#{departement[:name]})" } + end + + private + + def departements + @departements ||= APIGeoService.departements.sort_by { |departement| departement[:code] } + end +end diff --git a/app/models/types_de_champ/prefill_pays_type_de_champ.rb b/app/models/types_de_champ/prefill_pays_type_de_champ.rb index 143f041e7..6e5f9952c 100644 --- a/app/models/types_de_champ/prefill_pays_type_de_champ.rb +++ b/app/models/types_de_champ/prefill_pays_type_de_champ.rb @@ -3,10 +3,6 @@ class TypesDeChamp::PrefillPaysTypeDeChamp < TypesDeChamp::PrefillTypeDeChamp countries.map { |country| "#{country[:code]} (#{country[:name]})" } end - def example_value - countries.pick(:code) - end - private def countries diff --git a/app/models/types_de_champ/prefill_type_de_champ.rb b/app/models/types_de_champ/prefill_type_de_champ.rb index 296c04c48..5e9e55380 100644 --- a/app/models/types_de_champ/prefill_type_de_champ.rb +++ b/app/models/types_de_champ/prefill_type_de_champ.rb @@ -9,6 +9,8 @@ class TypesDeChamp::PrefillTypeDeChamp < SimpleDelegator TypesDeChamp::PrefillPaysTypeDeChamp.new(type_de_champ) when TypeDeChamp.type_champs.fetch(:regions) TypesDeChamp::PrefillRegionTypeDeChamp.new(type_de_champ) + when TypeDeChamp.type_champs.fetch(:departements) + TypesDeChamp::PrefillDepartementTypeDeChamp.new(type_de_champ) else new(type_de_champ) end diff --git a/config/locales/en.yml b/config/locales/en.yml index dc8be05ec..c9f4af19e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -130,6 +130,7 @@ en: yes_no_html: '"true" for Yes, "false" pour No' checkbox_html: '"true" to check, "false" to uncheck' pays_html: An ISO 3166-2 country code + departements_html: A department number regions_html: An INSEE region code date_html: ISO8601 date datetime_html: ISO8601 datetime @@ -145,6 +146,7 @@ en: iban: FR7611315000011234567890138 yes_no: "true" pays: "FR" + departements: "56" regions: "53" date: "2023-02-01" datetime: "2023-02-01T10:30" @@ -475,6 +477,12 @@ en: not_in_region_names: "must be a valid region name" external_id: not_in_region_codes: "must be a valid region code" + "champs/departement_champ": + attributes: + value: + not_in_departement_names: "must be a valid department name" + external_id: + not_in_departement_codes: "must be a valid department code" errors: format: "Field « %{attribute} » %{message}" messages: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index d4b864c28..b530475fc 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -121,6 +121,7 @@ fr: yes_no_html: '"true" pour Oui, "false" pour Non' checkbox_html: '"true" pour coché, "false" pour décoché' pays_html: Un code pays ISO 3166-2 + departements_html: Un numéro de département regions_html: Un code INSEE de région datetime_html: Datetime au format ISO8601 date_html: Date au format ISO8601 @@ -137,6 +138,7 @@ fr: yes_no: "true" civilite: "M." pays: "FR" + departements: "56" regions: "53" date: "2023-02-01" datetime: "2023-02-01T10:30" @@ -470,6 +472,12 @@ fr: not_in_region_names: "doit être un nom de région valide" external_id: not_in_region_codes: "doit être un code de région valide" + "champs/departement_champ": + attributes: + value: + not_in_departement_names: "doit être un nom de département valide" + external_id: + not_in_departement_codes: "doit être un code de département valide" errors: format: "Le champ « %{attribute} » %{message}" messages: diff --git a/spec/controllers/api/v1/dossiers_controller_spec.rb b/spec/controllers/api/v1/dossiers_controller_spec.rb index af705addd..9c7ef5fe3 100644 --- a/spec/controllers/api/v1/dossiers_controller_spec.rb +++ b/spec/controllers/api/v1/dossiers_controller_spec.rb @@ -4,6 +4,13 @@ describe API::V1::DossiersController do let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, administrateur: admin) } let(:wrong_procedure) { create(:procedure) } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + Rails.cache.clear + end + it { expect(described_class).to be < APIController } describe 'GET index (with bearer token)' do @@ -258,7 +265,7 @@ describe API::V1::DossiersController do end end - describe 'departement' do + describe 'departement', vcr: { cassette_name: 'api_geo_departements' } do let(:procedure) { create(:procedure, :with_departement, administrateur: admin) } let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure: procedure) } diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index acfe61304..6f70743cd 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -42,7 +42,6 @@ describe API::V2::GraphqlController do allow(Rails).to receive(:cache).and_return(memory_store) Rails.cache.clear - allow(APIGeoService).to receive(:departement_name).with('01').and_return('Ain') instructeur.assign_to_procedure(procedure) end @@ -397,7 +396,7 @@ describe API::V2::GraphqlController do dossier end - context "for individual", vcr: { cassette_name: 'api_geo_regions' } do + context "for individual", vcr: { cassette_name: 'api_geo_all' } do let(:procedure) { create(:procedure, :published, :for_individual, :with_service, :with_all_champs, :with_all_annotations, administrateurs: [admin]) } let(:query) do "{ diff --git a/spec/models/champs/departement_champ_spec.rb b/spec/models/champs/departement_champ_spec.rb index 35353f865..1a70439d5 100644 --- a/spec/models/champs/departement_champ_spec.rb +++ b/spec/models/champs/departement_champ_spec.rb @@ -6,9 +6,69 @@ describe Champs::DepartementChamp, type: :model do Rails.cache.clear end - let(:champ) { described_class.new } + describe 'validations', vcr: { cassette_name: 'api_geo_departements' } do + describe 'external link' do + subject { build(:champ_departements, external_id: external_id) } + + context 'when nil' do + let(:external_id) { nil } + + it { is_expected.to be_valid } + end + + context 'when blank' do + let(:external_id) { '' } + + it { is_expected.not_to be_valid } + end + + context 'when included in the departement codes' do + let(:external_id) { "01" } + + it { is_expected.to be_valid } + end + + context 'when not included in the departement codes' do + let(:external_id) { "totoro" } + + it { is_expected.not_to be_valid } + end + end + + describe 'value' do + subject { create(:champ_departements) } + + before { subject.update_columns(value: value) } + + context 'when nil' do + let(:value) { nil } + + it { is_expected.to be_valid } + end + + context 'when blank' do + let(:value) { '' } + + it { is_expected.not_to be_valid } + end + + context 'when included in the departement names' do + let(:value) { "Ain" } + + it { is_expected.to be_valid } + end + + context 'when not included in the departement names' do + let(:value) { "totoro" } + + it { is_expected.not_to be_valid } + end + end + end describe 'value', vcr: { cassette_name: 'api_geo_departements' } do + let(:champ) { described_class.new } + it 'with code having 2 chars' do champ.value = '01' expect(champ.external_id).to eq('01') diff --git a/spec/models/prefill_params_spec.rb b/spec/models/prefill_params_spec.rb index 84c99a26b..2c9ff077a 100644 --- a/spec/models/prefill_params_spec.rb +++ b/spec/models/prefill_params_spec.rb @@ -1,5 +1,5 @@ RSpec.describe PrefillParams do - describe "#to_a", vcr: { cassette_name: 'api_geo_regions' } do + describe "#to_a", vcr: { cassette_name: 'api_geo_all' } do let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } let(:procedure) { create(:procedure, :published, types_de_champ_public:, types_de_champ_private:) } @@ -126,6 +126,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", :drop_down_list, "value" it_behaves_like "a champ public value that is authorized", :regions, "03" + it_behaves_like "a champ public value that is authorized", :departements, "03" it_behaves_like "a champ private value that is authorized", :text, "value" it_behaves_like "a champ private value that is authorized", :textarea, "value" @@ -144,6 +145,7 @@ RSpec.describe PrefillParams do it_behaves_like "a champ private value that is authorized", :checkbox, "false" it_behaves_like "a champ private value that is authorized", :drop_down_list, "value" it_behaves_like "a champ private value that is authorized", :regions, "93" + it_behaves_like "a champ public value that is authorized", :departements, "03" it_behaves_like "a champ public value that is unauthorized", :decimal_number, "non decimal string" it_behaves_like "a champ public value that is unauthorized", :integer_number, "non integer string" diff --git a/spec/models/type_de_champ_spec.rb b/spec/models/type_de_champ_spec.rb index e1ca7bac6..9d891f5e1 100644 --- a/spec/models/type_de_champ_spec.rb +++ b/spec/models/type_de_champ_spec.rb @@ -250,6 +250,7 @@ describe TypeDeChamp do it_behaves_like "a prefillable type de champ", :type_de_champ_checkbox it_behaves_like "a prefillable type de champ", :type_de_champ_drop_down_list it_behaves_like "a prefillable type de champ", :type_de_champ_regions + it_behaves_like "a prefillable type de champ", :type_de_champ_departements it_behaves_like "a non-prefillable type de champ", :type_de_champ_number it_behaves_like "a non-prefillable type de champ", :type_de_champ_communes @@ -267,7 +268,6 @@ describe TypeDeChamp do it_behaves_like "a non-prefillable type de champ", :type_de_champ_mesri it_behaves_like "a non-prefillable type de champ", :type_de_champ_carte it_behaves_like "a non-prefillable type de champ", :type_de_champ_address - it_behaves_like "a non-prefillable type de champ", :type_de_champ_departements it_behaves_like "a non-prefillable type de champ", :type_de_champ_siret it_behaves_like "a non-prefillable type de champ", :type_de_champ_rna it_behaves_like "a non-prefillable type de champ", :type_de_champ_annuaire_education diff --git a/spec/models/types_de_champ/prefill_departement_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_departement_type_de_champ_spec.rb new file mode 100644 index 000000000..f43a07393 --- /dev/null +++ b/spec/models/types_de_champ/prefill_departement_type_de_champ_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +RSpec.describe TypesDeChamp::PrefillDepartementTypeDeChamp, type: :model do + let(:type_de_champ) { build(:type_de_champ_departements) } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + Rails.cache.clear + end + + describe 'ancestors' do + subject { described_class.build(type_de_champ) } + + it { is_expected.to be_kind_of(TypesDeChamp::PrefillTypeDeChamp) } + end + + describe '#possible_values', vcr: { cassette_name: 'api_geo_departements' } do + let(:expected_values) { + APIGeoService.departements.sort_by { |departement| departement[:code] }.map { |departement| "#{departement[:code]} (#{departement[:name]})" } + } + subject(:possible_values) { described_class.new(type_de_champ).possible_values } + + it { expect(possible_values).to match(expected_values) } + end +end diff --git a/spec/models/types_de_champ/prefill_pays_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_pays_type_de_champ_spec.rb index f651d3d60..67789ba9e 100644 --- a/spec/models/types_de_champ/prefill_pays_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_pays_type_de_champ_spec.rb @@ -2,16 +2,16 @@ RSpec.describe TypesDeChamp::PrefillPaysTypeDeChamp, type: :model do let(:type_de_champ) { build(:type_de_champ_pays) } + describe 'ancestors' do + subject { described_class.build(type_de_champ) } + + it { is_expected.to be_kind_of(TypesDeChamp::PrefillTypeDeChamp) } + end + describe '#possible_values' do let(:expected_values) { APIGeoService.countries.sort_by { |country| country[:code] }.map { |country| "#{country[:code]} (#{country[:name]})" } } subject(:possible_values) { described_class.new(type_de_champ).possible_values } it { expect(possible_values).to match(expected_values) } end - - describe '#example_value' do - subject(:example_value) { described_class.new(type_de_champ).example_value } - - it { expect(example_value).to eq(APIGeoService.countries.sort_by { |country| country[:code] }.first[:code]) } - end end diff --git a/spec/models/types_de_champ/prefill_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_type_de_champ_spec.rb index af0e3cfc9..52508be91 100644 --- a/spec/models/types_de_champ/prefill_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_type_de_champ_spec.rb @@ -22,6 +22,12 @@ RSpec.describe TypesDeChamp::PrefillTypeDeChamp, type: :model do it { expect(built).to be_kind_of(TypesDeChamp::PrefillRegionTypeDeChamp) } end + context 'when the type de champ is a departements' do + let(:type_de_champ) { build(:type_de_champ_departements) } + + it { expect(built).to be_kind_of(TypesDeChamp::PrefillDepartementTypeDeChamp) } + end + context 'when any other type de champ' do let(:type_de_champ) { build(:type_de_champ_date) }