Affiche un message d'erreur clair lorsque l'API-Entreprise est indisponible (#3831)

Un message d'erreur clair est affiché lorsque la récupération des informations à partir du n° SIRET est temporairement indisponible
This commit is contained in:
Pierre de La Morinerie 2019-05-02 13:30:32 +02:00 committed by GitHub
commit 011b575900
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 173 additions and 82 deletions

View file

@ -7,25 +7,25 @@ class Champs::SiretController < ApplicationController
find_etablisement
if @siret.empty?
@champ&.update!(value: '')
@etablissement&.destroy
elsif @siret.present? && @siret.length == 14
etablissement = find_etablisement_with_siret
if etablissement.present?
@etablissement = etablissement
return clear_siret_and_etablissement
end
if !@champ.nil?
@champ.update!(value: etablissement.siret, etablissement: etablissement)
end
else
@champ&.update!(value: '')
@etablissement&.destroy
@siret = :not_found
end
else
@champ&.update!(value: '')
@etablissement&.destroy
@siret = :invalid
if @siret.present? && @siret.length != 14
return siret_error(:invalid)
end
begin
etablissement = find_etablissement_with_siret
rescue RestClient::RequestFailed
return siret_error(:network_error)
end
if etablissement.blank?
return siret_error(:not_found)
end
@etablissement = etablissement
if !@champ.nil?
@champ.update!(value: etablissement.siret, etablissement: etablissement)
end
end
@ -49,10 +49,20 @@ class Champs::SiretController < ApplicationController
@procedure_id = @champ&.dossier&.procedure_id || 'aperçu'
end
def find_etablisement_with_siret
def find_etablissement_with_siret
etablissement_attributes = ApiEntrepriseService.get_etablissement_params_for_siret(@siret, @procedure_id)
if etablissement_attributes.present?
Etablissement.new(etablissement_attributes)
end
end
def clear_siret_and_etablissement
@champ&.update!(value: '')
@etablissement&.destroy
end
def siret_error(error)
clear_siret_and_etablissement
@siret = error
end
end

View file

@ -91,7 +91,11 @@ module Users
end
sanitized_siret = siret_model.siret
etablissement_attributes = ApiEntrepriseService.get_etablissement_params_for_siret(sanitized_siret, @dossier.procedure.id)
begin
etablissement_attributes = ApiEntrepriseService.get_etablissement_params_for_siret(sanitized_siret, @dossier.procedure.id)
rescue RestClient::RequestFailed
return render_siret_error(t('errors.messages.siret_network_error'))
end
if etablissement_attributes.blank?
return render_siret_error(t('errors.messages.siret_unknown'))
end

View file

@ -2,7 +2,11 @@ class EtablissementUpdateJob < ApplicationJob
queue_as :default
def perform(dossier, siret)
etablissement_attributes = ApiEntrepriseService.get_etablissement_params_for_siret(siret, dossier.procedure_id)
begin
etablissement_attributes = ApiEntrepriseService.get_etablissement_params_for_siret(siret, dossier.procedure_id)
rescue
return
end
if etablissement_attributes.present?
if dossier.etablissement.present?

View file

@ -7,9 +7,11 @@ class ApiEntreprise::Adapter
end
def data_source
@data_source ||= get_resource
rescue
@data_source = nil
begin
@data_source ||= get_resource
rescue RestClient::ResourceNotFound
@data_source = nil
end
end
def to_params

View file

@ -34,8 +34,10 @@ class ApiEntreprise::API
if response.success?
JSON.parse(response.body, symbolize_names: true)
else
elsif response.code == 404 || response.code == 422
raise RestClient::ResourceNotFound
else
raise RestClient::RequestFailed
end
end

View file

@ -1,4 +1,11 @@
class ApiEntrepriseService
# Retrieve all informations we can get about a SIRET.
#
# Returns nil if the SIRET is unknown; and nested params
# suitable for being saved into a Etablissement object otherwise.
#
# Raises a RestClient::RequestFailed exception on transcient errors
# (timeout, 5XX HTTP error code, etc.)
def self.get_etablissement_params_for_siret(siret, procedure_id)
etablissement_params = ApiEntreprise::EtablissementAdapter.new(siret, procedure_id).to_params
entreprise_params = ApiEntreprise::EntrepriseAdapter.new(siret, procedure_id).to_params

View file

@ -6,6 +6,9 @@
Nous navons pas trouvé détablissement correspondant à ce numéro de SIRET.
= link_to('Plus dinformations', "https://faq.demarches-simplifiees.fr/article/4-erreur-siret", target: '_blank', rel: 'noopener')
- when :network_error
= t('errors.messages.siret_network_error')
- else
- if siret.present? && siret == etablissement&.siret
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: etablissement }

View file

@ -182,7 +182,8 @@ fr:
dossier_map_not_activated: "Le dossier n'a pas accès à la cartographie."
invalid_siret: "Le siret est incorrect"
procedure_not_found: "La démarche n'existe pas"
siret_unknown: 'Désolé, nous navons pas trouvé détablissement enregistré correspondant à ce numéro SIRET'
siret_unknown: 'Désolé, nous navons 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.'
etablissement_fail: 'Désolé, nous navons pas réussi à enregistrer létablissement correspondant à ce numéro SIRET'
france_connect:
connexion: "Erreur lors de la connexion à France Connect."

View file

@ -20,74 +20,105 @@ describe Champs::SiretController, type: :controller do
end
let(:siret) { '' }
context 'when user is connected' do
context 'when the user is signed in' do
render_views
before { sign_in user }
context 'when siret empty' do
before {
get :show, params: params, format: 'js'
}
context 'when the SIRET is empty' do
subject! { get :show, params: params, format: 'js' }
it 'empty info message' do
it 'clears the etablissement and SIRET on the model' do
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
it 'clears any information or error message' do
expect(response.body).to include('.siret-info-1')
expect(response.body).to include('innerHTML = ""')
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
end
context 'when siret invalid' do
context 'when the SIRET is invalid' do
let(:siret) { '1234' }
before {
get :show, params: params, format: 'js'
}
it 'invalid error' do
subject! { get :show, params: params, format: 'js' }
it 'clears the etablissement and SIRET on the model' do
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
it 'displays a “SIRET is invalid” error message' do
expect(response.body).to include('Le numéro de SIRET doit comporter exactement 14 chiffres.')
end
end
context 'when the API is unavailable' do
let(:siret) { '82161143100015' }
before do
allow(controller).to receive(:find_etablissement_with_siret).and_raise(RestClient::RequestFailed)
end
subject! { get :show, params: params, format: 'js' }
it 'clears the etablissement and SIRET on the model' do
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
it 'displays a “API is unavailable” error message' do
expect(response.body).to include(I18n.t('errors.messages.siret_network_error'))
end
end
context 'when siret not found' do
let(:siret) { '0' * 14 }
before {
expect(subject).to receive(:find_etablisement_with_siret).and_return(false)
get :show, params: params, format: 'js'
}
context 'when the SIRET is valid but unknown' do
let(:siret) { '00000000000000' }
it 'not found error' do
before do
allow(controller).to receive(:find_etablissement_with_siret).and_return(false)
end
subject! { get :show, params: params, format: 'js' }
it 'clears the etablissement and SIRET on the model' do
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
it 'displays a “SIRET not found” error message' do
expect(response.body).to include('Nous navons pas trouvé détablissement correspondant à ce numéro de SIRET.')
champ.reload
expect(champ.etablissement).to be_nil
expect(champ.value).to be_empty
end
end
context 'when siret found' do
context 'when the SIRET informations are retrieved successfully' do
let(:siret) { etablissement.siret }
let(:etablissement) { build(:etablissement) }
before {
expect(subject).to receive(:find_etablisement_with_siret).and_return(etablissement)
get :show, params: params, format: 'js'
}
it 'etablissement info message' do
expect(response.body).to include(etablissement.entreprise_raison_sociale)
before do
allow(controller).to receive(:find_etablissement_with_siret).and_return(etablissement)
end
subject! { get :show, params: params, format: 'js' }
it 'populates the etablissement and SIRET on the model' do
champ.reload
expect(champ.value).to eq(etablissement.siret)
expect(champ.etablissement.siret).to eq(etablissement.siret)
end
it 'displays the name of the company' do
expect(response.body).to include(etablissement.entreprise_raison_sociale)
end
end
end
context 'when user is not connected' do
before {
get :show, params: { position: '1' }, format: 'js'
}
context 'when user is not signed in' do
subject! { get :show, params: { position: '1' }, format: 'js' }
it { expect(response.code).to eq('401') }
end

View file

@ -278,6 +278,13 @@ describe Users::DossiersController, type: :controller do
context 'with a valid SIRET' do
let(:params_siret) { '440 117 620 01530' }
context 'When API-Entreprise is down' do
let(:api_etablissement_status) { 502 }
let(:api_body_status) { File.read('spec/fixtures/files/api_entreprise/exercices_unavailable.json') }
it_behaves_like 'the request fails with an error', I18n.t('errors.messages.siret_network_error')
end
context 'when API-Entreprise doesnt know this SIRET' do
let(:api_etablissement_status) { 404 }
let(:api_body_status) { '' }

View file

@ -0,0 +1,7 @@
{
"errors": [
"Erreur interne du serveur",
"Le siret ou siren indiqué n'existe pas, n'est pas connu ou ne comporte aucune information pour cet appel"
],
"gateway_error": true
}

View file

@ -2,21 +2,35 @@ require 'spec_helper'
describe ApiEntreprise::API do
let(:procedure_id) { 12 }
describe '.entreprise' do
subject { described_class.entreprise(siren, procedure_id) }
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: status, body: body)
end
context 'when the service is unavailable' do
let(:siren) { '111111111' }
let(:status) { 502 }
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_unavailable.json') }
it 'raises RestClient::RequestFailed' do
expect { subject }.to raise_error(RestClient::RequestFailed)
end
end
context 'when siren does not exist' do
let(:siren) { '111111111' }
let(:status) { 404 }
let(:body) { '' }
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_not_found.json') }
it 'raises RestClient::ResourceNotFound' do
expect { subject }.to raise_error(RestClient::ResourceNotFound)
end
end
context 'when siret exist' do
let(:siren) { '418166096' }
let(:status) { 200 }

View file

@ -11,7 +11,7 @@ describe ApiEntreprise::EntrepriseAdapter do
.to_return(body: body, status: status)
end
context "when SIRET is OK" do
context "when the SIRET is valid" do
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises.json') }
let(:status) { 200 }
@ -70,12 +70,21 @@ describe ApiEntreprise::EntrepriseAdapter do
end
end
context "when SIRET is KO" do
context "when the SIRET is unknown" do
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_not_found.json') }
let(:status) { 206 }
let(:status) { 404 }
it '#to_params class est une Hash ?' do
expect(subject).to eq({})
end
end
context "when the service is unavailable" do
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_unavailable.json') }
let(:status) { 502 }
it 'raises an exception' do
expect { subject }.to raise_error(RestClient::RequestFailed)
end
end
end

View file

@ -10,25 +10,15 @@ describe ApiEntreprise::ExercicesAdapter do
.to_return(body: File.read('spec/fixtures/files/api_entreprise/exercices.json', status: 200))
end
it '#to_params class est un Hash ?' do
expect(subject).to be_an_instance_of(Hash)
end
it { is_expected.to be_an_instance_of(Hash) }
it 'have 3 exercices' do
it 'contains several exercices attributes' do
expect(subject[:exercices_attributes].size).to eq(3)
end
context 'Attributs Exercices' do
it 'L\'exercice contient bien un ca' do
expect(subject[:exercices_attributes][0][:ca]).to eq('21009417')
end
it 'L\'exercice contient bien une date de fin d\'exercice' do
expect(subject[:exercices_attributes][0][:date_fin_exercice]).to eq("2013-12-31T00:00:00+01:00")
end
it 'L\'exercice contient bien une date_fin_exercice_timestamp' do
expect(subject[:exercices_attributes][0][:date_fin_exercice_timestamp]).to eq(1388444400)
end
it 'contains informations in each exercices_attributes' do
expect(subject[:exercices_attributes][0][:ca]).to eq('21009417')
expect(subject[:exercices_attributes][0][:date_fin_exercice]).to eq("2013-12-31T00:00:00+01:00")
expect(subject[:exercices_attributes][0][:date_fin_exercice_timestamp]).to eq(1388444400)
end
end

View file

@ -17,7 +17,7 @@ describe ApiEntreprise::RNAAdapter do
context 'when siret is not valid' do
let(:siret) { '234567' }
let(:body) { '' }
let(:status) { '404' }
let(:status) { 404 }
it { is_expected.to eq({}) }
end