From 5876dab0960d58c77df4ce452c14c7b1563cf295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Carceles?= Date: Mon, 9 Jan 2023 15:29:18 +0100 Subject: [PATCH] siret champ can fetch it's own etablissement --- app/models/champs/siret_champ.rb | 2 + ...t_champ_etablissement_fetchable_concern.rb | 34 +++++++ ...mp_etablissement_fetchable_concern_spec.rb | 94 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 app/models/concerns/siret_champ_etablissement_fetchable_concern.rb create mode 100644 spec/models/concern/siret_champ_etablissement_fetchable_concern_spec.rb diff --git a/app/models/champs/siret_champ.rb b/app/models/champs/siret_champ.rb index 97c816fbf..0901c3227 100644 --- a/app/models/champs/siret_champ.rb +++ b/app/models/champs/siret_champ.rb @@ -21,6 +21,8 @@ # type_de_champ_id :integer # class Champs::SiretChamp < Champ + include SiretChampEtablissementFetchableConcern + def search_terms etablissement.present? ? etablissement.search_terms : [value] end diff --git a/app/models/concerns/siret_champ_etablissement_fetchable_concern.rb b/app/models/concerns/siret_champ_etablissement_fetchable_concern.rb new file mode 100644 index 000000000..8d53f0a4c --- /dev/null +++ b/app/models/concerns/siret_champ_etablissement_fetchable_concern.rb @@ -0,0 +1,34 @@ +module SiretChampEtablissementFetchableConcern + extend ActiveSupport::Concern + + def fetch_etablissement!(siret, user) + return clear if siret.empty? + return clear(error: :invalid) unless Siret.new(siret: siret).valid? # i18n-tasks-use t('errors.messages.invalid_siret') + return clear(error: :not_found) unless (etablissement = APIEntrepriseService.create_etablissement(self, siret, user.id)) # i18n-tasks-use t('errors.messages.siret_not_found') + + return update_etablissement!(etablissement) + rescue => error + if error.try(:network_error?) && !APIEntrepriseService.api_up? + # TODO: notify ops + etablissement = APIEntrepriseService.create_etablissement_as_degraded_mode(self, siret, user.id) + return update_etablissement!(etablissement, error: :api_entreprise_down) + else + Sentry.capture_exception(error, extra: { dossier_id: dossier_id, siret: siret }) + return clear(error: :network_error) # i18n-tasks-use t('errors.messages.siret_network_error') + end + end + + private + + def update_etablissement!(etablissement, error: nil) + update!(value: etablissement.siret, etablissement: etablissement) + error.presence || etablissement.siret + end + + def clear(error: nil) + etablissement_to_destroy = etablissement + update!(value: '', etablissement: nil) + etablissement_to_destroy&.destroy + error.presence + end +end diff --git a/spec/models/concern/siret_champ_etablissement_fetchable_concern_spec.rb b/spec/models/concern/siret_champ_etablissement_fetchable_concern_spec.rb new file mode 100644 index 000000000..77b754dac --- /dev/null +++ b/spec/models/concern/siret_champ_etablissement_fetchable_concern_spec.rb @@ -0,0 +1,94 @@ +RSpec.describe SiretChampEtablissementFetchableConcern do + describe '.fetch_etablissement!' do + let(:api_etablissement_status) { 200 } + let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') } + let(:token_expired) { false } + let!(:champ) { create(:champ_siret) } + + before do + stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/) + .to_return(status: api_etablissement_status, body: api_etablissement_body) + allow_any_instance_of(APIEntrepriseToken).to receive(:roles) + .and_return(["attestations_fiscales", "attestations_sociales", "bilans_entreprise_bdf"]) + allow_any_instance_of(APIEntrepriseToken).to receive(:expired?).and_return(token_expired) + end + + subject(:fetch_etablissement!) { champ.fetch_etablissement!(siret, build_stubbed(:user)) } + + shared_examples 'an error occured' do |error| + it { expect { fetch_etablissement! }.to change { champ.reload.value }.to('') } + + it { expect { fetch_etablissement! }.to change { champ.reload.etablissement }.to(nil) } + + it { expect { fetch_etablissement! }.to change { Etablissement.count }.by(-1) } + + it { expect(fetch_etablissement!).to eq(error) } + end + + context 'when the SIRET is empty' do + let(:siret) { '' } + + it_behaves_like 'an error occured', nil + end + + context 'when the SIRET is invalid' do + let(:siret) { '1234' } + + it_behaves_like 'an error occured', :invalid + end + + context 'when the API is unavailable due to network error' do + let(:siret) { '82161143100015' } + let(:api_etablissement_status) { 503 } + + before { expect(APIEntrepriseService).to receive(:api_up?).and_return(true) } + + it_behaves_like 'an error occured', :network_error + + it 'sends the error to Sentry' do + expect(Sentry).to receive(:capture_exception) + fetch_etablissement! + end + end + + context 'when the API is unavailable due to an api maintenance or pb' do + let(:siret) { '82161143100015' } + let(:api_etablissement_status) { 502 } + + before { expect(APIEntrepriseService).to receive(:api_up?).and_return(false) } + + it { expect { fetch_etablissement! }.to change { champ.reload.value }.to(siret) } + + it { expect { fetch_etablissement! }.to change { champ.reload.etablissement } } + + it { expect { fetch_etablissement! }.to change { champ.reload.etablissement.as_degraded_mode? }.to(true) } + + it { expect { fetch_etablissement! }.to change { Etablissement.count }.by(1) } + + it { expect(fetch_etablissement!).to eq(:api_entreprise_down) } + end + + context 'when the SIRET is valid but unknown' do + let(:siret) { '00000000000000' } + let(:api_etablissement_status) { 404 } + + it_behaves_like 'an error occured', :not_found + end + + context 'when the SIRET informations are retrieved successfully' do + let(:siret) { '41816609600051' } + let(:api_etablissement_status) { 200 } + let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') } + + it { expect { fetch_etablissement! }.to change { champ.reload.value }.to(siret) } + + it { expect { fetch_etablissement! }.to change { champ.reload.etablissement.siret }.to(siret) } + + it { expect { fetch_etablissement! }.to change { champ.reload.etablissement.naf }.to("6202A") } + + it { expect { fetch_etablissement! }.to change { Etablissement.count }.by(1) } + + it { expect(fetch_etablissement!).to eq(siret) } + end + end +end