feat(api_entreprise): create etablissement with fallback when API is down
On créé l'établissement uniquement avec le SIRET, sans que ce soit bloquant pour compléter le dossier. On demande à l'utilisateur de vérifier lui-même la concordance du SIRET avec son entreprise. Cf #7766
This commit is contained in:
parent
3cd02ceae3
commit
95a4e8a907
11 changed files with 141 additions and 54 deletions
|
@ -112,18 +112,20 @@ module Users
|
||||||
end
|
end
|
||||||
|
|
||||||
sanitized_siret = siret_model.siret
|
sanitized_siret = siret_model.siret
|
||||||
begin
|
etablissement = begin
|
||||||
etablissement = APIEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id)
|
APIEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id)
|
||||||
rescue APIEntreprise::API::Error::RequestFailed, APIEntreprise::API::Error::BadGateway, APIEntreprise::API::Error::TimedOut, APIEntreprise::API::Error::ServiceUnavailable, APIEntrepriseToken::TokenError => e
|
rescue => error
|
||||||
if e.is_a?(APIEntrepriseToken::TokenError) || APIEntrepriseService.api_up?
|
if error.try(:network_error?) && !APIEntrepriseService.api_up?
|
||||||
# probably random error, invite user to retry
|
# TODO: notify ops
|
||||||
Sentry.capture_exception(e, extra: { dossier_id: @dossier.id, siret: sanitized_siret })
|
APIEntrepriseService.create_etablissement_as_degraded_mode(@dossier, sanitized_siret, current_user.id)
|
||||||
return render_siret_error(t('errors.messages.siret_network_error'))
|
|
||||||
else
|
else
|
||||||
# global API Entreprise error. TODO: degraded mode + notify ops
|
Sentry.capture_exception(error, extra: { dossier_id: @dossier.id, siret: })
|
||||||
return render_siret_error(t('errors.messages.siret_api_down'))
|
|
||||||
|
# probably random error, invite user to retry
|
||||||
|
return render_siret_error(t('errors.messages.siret_network_error'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if etablissement.nil?
|
if etablissement.nil?
|
||||||
return render_siret_error(t('errors.messages.siret_unknown'))
|
return render_siret_error(t('errors.messages.siret_unknown'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,4 +15,8 @@ class APIEntreprise::API::Error < ::StandardError
|
||||||
|
|
||||||
super(msg)
|
super(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def network_error?
|
||||||
|
true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
class APIEntreprise::API::Error::BadFormatRequest < APIEntreprise::API::Error
|
class APIEntreprise::API::Error::BadFormatRequest < APIEntreprise::API::Error
|
||||||
|
def network_error?
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
class APIEntreprise::API::Error::ResourceNotFound < APIEntreprise::API::Error
|
class APIEntreprise::API::Error::ResourceNotFound < APIEntreprise::API::Error
|
||||||
|
def network_error?
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -222,6 +222,10 @@ class Etablissement < ApplicationRecord
|
||||||
SpreadsheetArchitect.send("to_#{format}".to_sym, bilans_bdf_data)
|
SpreadsheetArchitect.send("to_#{format}".to_sym, bilans_bdf_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def as_degraded_mode?
|
||||||
|
adresse.nil? # TOOD: maybe dedicated column or more robust way
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def bilans_new_keys
|
def bilans_new_keys
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class APIEntrepriseService
|
class APIEntrepriseService
|
||||||
|
class << self
|
||||||
# create etablissement with EtablissementAdapter
|
# create etablissement with EtablissementAdapter
|
||||||
# enqueue api_entreprise jobs to retrieve
|
# enqueue api_entreprise jobs to retrieve
|
||||||
# all informations we can get about a SIRET.
|
# all informations we can get about a SIRET.
|
||||||
|
@ -7,26 +8,45 @@ class APIEntrepriseService
|
||||||
#
|
#
|
||||||
# Raises a APIEntreprise::API::Error::RequestFailed exception on transient errors
|
# Raises a APIEntreprise::API::Error::RequestFailed exception on transient errors
|
||||||
# (timeout, 5XX HTTP error code, etc.)
|
# (timeout, 5XX HTTP error code, etc.)
|
||||||
def self.create_etablissement(dossier_or_champ, siret, user_id = nil)
|
#
|
||||||
etablissement_params = APIEntreprise::EtablissementAdapter.new(siret, dossier_or_champ.procedure.id).to_params
|
def create_etablissement(dossier_or_champ, siret, user_id = nil)
|
||||||
|
procedure_id = dossier_or_champ.procedure.id
|
||||||
|
|
||||||
|
etablissement_params = APIEntreprise::EtablissementAdapter.new(siret, procedure_id).to_params
|
||||||
return nil if etablissement_params.empty?
|
return nil if etablissement_params.empty?
|
||||||
|
|
||||||
etablissement = dossier_or_champ.build_etablissement(etablissement_params)
|
etablissement = dossier_or_champ.build_etablissement(etablissement_params)
|
||||||
etablissement.save!
|
etablissement.save!
|
||||||
|
|
||||||
|
perform_later_fetch_jobs(etablissement, procedure_id, user_id)
|
||||||
|
|
||||||
|
etablissement
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_etablissement_as_degraded_mode(dossier_or_champ, siret, user_id = nil)
|
||||||
|
etablissement = dossier_or_champ.build_etablissement(siret: siret)
|
||||||
|
etablissement.save!
|
||||||
|
|
||||||
|
procedure_id = dossier_or_champ.procedure.id
|
||||||
|
|
||||||
|
perform_later_fetch_jobs(etablissement, procedure_id, user_id, wait: 30.minutes)
|
||||||
|
|
||||||
|
etablissement
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform_later_fetch_jobs(etablissement, procedure_id, user_id, wait: nil)
|
||||||
[
|
[
|
||||||
APIEntreprise::EntrepriseJob, APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
|
APIEntreprise::EntrepriseJob, APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
|
||||||
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
|
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
|
||||||
APIEntreprise::BilansBdfJob
|
APIEntreprise::BilansBdfJob
|
||||||
].each do |job|
|
].each do |job|
|
||||||
job.perform_later(etablissement.id, dossier_or_champ.procedure.id)
|
job.set(wait:).perform_later(etablissement.id, procedure_id)
|
||||||
end
|
|
||||||
APIEntreprise::AttestationFiscaleJob.perform_later(etablissement.id, dossier_or_champ.procedure.id, user_id)
|
|
||||||
|
|
||||||
etablissement
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.api_up?(uname = "apie_2_etablissements")
|
APIEntreprise::AttestationFiscaleJob.set(wait:).perform_later(etablissement.id, procedure_id, user_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_up?(uname = "apie_2_etablissements")
|
||||||
statuses = APIEntreprise::API.new.current_status.fetch(:results)
|
statuses = APIEntreprise::API.new.current_status.fetch(:results)
|
||||||
|
|
||||||
# find results having uname = apie_2_etablissements
|
# find results having uname = apie_2_etablissements
|
||||||
|
@ -38,4 +58,5 @@ class APIEntrepriseService
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,23 @@
|
||||||
%h1 Informations sur l’établissement
|
%h1 Informations sur l’établissement
|
||||||
|
|
||||||
- etablissement = @dossier.etablissement
|
- etablissement = @dossier.etablissement
|
||||||
- if etablissement.diffusable_commercialement == false
|
|
||||||
|
- if etablissement.as_degraded_mode?
|
||||||
|
= render Dsfr::CalloutComponent.new(title: "Nous n'avons pas pu vérifier votre SIRET", theme: :warning, icon: "fr-icon-feedback-fill") do |c|
|
||||||
|
- c.with_body do
|
||||||
|
%p
|
||||||
|
L'annuaire INSEE est indisponible, nous ne pouvons pas vérifier votre SIRET.
|
||||||
|
%br
|
||||||
|
%br
|
||||||
|
Veuillez vérifier par vous-même que le numéro
|
||||||
|
%strong= etablissement.siret
|
||||||
|
correspond bien à votre entreprise :
|
||||||
|
|
||||||
|
%p
|
||||||
|
= link_to annuaire_link(etablissement.siret), class: "fr-btn fr-btn--secondary", **external_link_attributes do
|
||||||
|
Vérifier dans l'annuaire des entreprises
|
||||||
|
|
||||||
|
- elsif etablissement.diffusable_commercialement == false
|
||||||
%p= t('warning_for_private_info', scope: 'views.shared.dossiers.identite_entreprise', etablissement: raison_sociale_or_name(etablissement))
|
%p= t('warning_for_private_info', scope: 'views.shared.dossiers.identite_entreprise', etablissement: raison_sociale_or_name(etablissement))
|
||||||
|
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -370,7 +370,6 @@ fr:
|
||||||
procedure_not_found: "La démarche n’existe pas"
|
procedure_not_found: "La démarche n’existe pas"
|
||||||
siret_unknown: 'Désolé, nous n’avons pas trouvé d’établissement enregistré correspondant à ce numéro SIRET.'
|
siret_unknown: 'Désolé, nous n’avons pas trouvé d’établissement enregistré correspondant à ce numéro SIRET.'
|
||||||
siret_network_error: 'Désolé, la récupération des informations SIRET est temporairement indisponible. Veuillez réessayer dans quelques instants.'
|
siret_network_error: 'Désolé, la récupération des informations SIRET est temporairement indisponible. Veuillez réessayer dans quelques instants.'
|
||||||
siret_api_down: "L'INSEE rencontre actuellement un problème majeur qui empêche le traitement des informations SIRET. Il n'y a pas encore de date de résolution annoncée."
|
|
||||||
siret_not_found: 'Nous n’avons pas trouvé d’établissement correspondant à ce numéro de SIRET.'
|
siret_not_found: 'Nous n’avons pas trouvé d’établissement correspondant à ce numéro de SIRET.'
|
||||||
# etablissement_fail: 'Désolé, nous n’avons pas réussi à enregistrer l’établissement correspondant à ce numéro SIRET'
|
# etablissement_fail: 'Désolé, nous n’avons pas réussi à enregistrer l’établissement correspondant à ce numéro SIRET'
|
||||||
france_connect:
|
france_connect:
|
||||||
|
|
|
@ -273,7 +273,11 @@ describe Users::DossiersController, type: :controller do
|
||||||
let(:api_etablissement_status) { 502 }
|
let(:api_etablissement_status) { 502 }
|
||||||
let(:api_current_status_response) { File.read('spec/fixtures/files/api_entreprise/current_status.json').tr('200', '502') }
|
let(:api_current_status_response) { File.read('spec/fixtures/files/api_entreprise/current_status.json').tr('200', '502') }
|
||||||
|
|
||||||
it_behaves_like 'the request fails with an error', I18n.t('errors.messages.siret_api_down')
|
it "create an etablissement only with SIRET as degraded mode" do
|
||||||
|
dossier.reload
|
||||||
|
expect(dossier.etablissement.siret).to eq(siret)
|
||||||
|
expect(dossier.etablissement).to be_as_degraded_mode
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when API-Entreprise doesn’t know this SIRET' do
|
context 'when API-Entreprise doesn’t know this SIRET' do
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
describe APIEntrepriseService do
|
describe APIEntrepriseService do
|
||||||
|
shared_examples 'schedule fetch of all etablissement params' do
|
||||||
|
[
|
||||||
|
APIEntreprise::EntrepriseJob, APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
|
||||||
|
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
|
||||||
|
APIEntreprise::BilansBdfJob
|
||||||
|
].each do |job|
|
||||||
|
it "should enqueue #{job.class.name}" do
|
||||||
|
expect { subject }.to have_enqueued_job(job)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#create_etablissement' do
|
describe '#create_etablissement' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/)
|
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/)
|
||||||
|
@ -23,15 +35,7 @@ describe APIEntrepriseService do
|
||||||
expect(subject[:siret]).to eq(siret)
|
expect(subject[:siret]).to eq(siret)
|
||||||
end
|
end
|
||||||
|
|
||||||
[
|
it_behaves_like 'schedule fetch of all etablissement params'
|
||||||
APIEntreprise::EntrepriseJob, APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
|
|
||||||
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
|
|
||||||
APIEntreprise::BilansBdfJob
|
|
||||||
].each do |job|
|
|
||||||
it "should enqueue #{job.class.name}" do
|
|
||||||
expect { subject }.to have_enqueued_job(job)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when etablissement api down' do
|
context 'when etablissement api down' do
|
||||||
|
@ -53,6 +57,24 @@ describe APIEntrepriseService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#create_etablissement_as_degraded_mode' do
|
||||||
|
let(:siret) { '41816609600051' }
|
||||||
|
let(:procedure) { create(:procedure) }
|
||||||
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
let(:user_id) { 12 }
|
||||||
|
|
||||||
|
subject(:etablissement) { APIEntrepriseService.create_etablissement_as_degraded_mode(dossier, siret, user_id) }
|
||||||
|
|
||||||
|
it 'should create an etablissement with minimumal attributes' do
|
||||||
|
etablissement = subject
|
||||||
|
|
||||||
|
expect(etablissement.siret).to eq(siret)
|
||||||
|
expect(etablissement).to be_as_degraded_mode
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'schedule fetch of all etablissement params'
|
||||||
|
end
|
||||||
|
|
||||||
describe "#api_up?" do
|
describe "#api_up?" do
|
||||||
subject { described_class.api_up? }
|
subject { described_class.api_up? }
|
||||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/current_status.json') }
|
let(:body) { File.read('spec/fixtures/files/api_entreprise/current_status.json') }
|
||||||
|
|
|
@ -27,4 +27,13 @@ describe 'users/dossiers/etablissement.html.haml', type: :view do
|
||||||
it 'prépare le footer' do
|
it 'prépare le footer' do
|
||||||
expect(footer).to have_selector('footer')
|
expect(footer).to have_selector('footer')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'etablissement as degraded mode' do
|
||||||
|
let(:etablissement) { Etablissement.create!(siret: '41816609600051') }
|
||||||
|
|
||||||
|
it "affiche une notice avec un lien de vérification vers l'annuaire" do
|
||||||
|
expect(rendered).to have_text(etablissement.siret)
|
||||||
|
expect(rendered).to have_link("Vérifier dans l'annuaire des entreprises", href: "https://annuaire-entreprises\.data\.gouv\.fr/rechercher?terme=#{etablissement.siret}")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue