dossiers: avoid exceptions on invalid AASM transitions

When attempting an invalid transition on a dossier, provide a meaningful
error message (instead of letting an `AASM::InvalidTransition` exception
propagate).

This handles not only the case where the same state is applied twice
(which was already handled manually), but all cases where the transition
is invalid.
This commit is contained in:
Pierre de La Morinerie 2019-12-19 13:25:32 +01:00
parent c7a307553c
commit 8eb295d67e
2 changed files with 47 additions and 17 deletions

View file

@ -88,33 +88,33 @@ module Instructeurs
end end
def passer_en_instruction def passer_en_instruction
if dossier.en_instruction? begin
flash.notice = 'Le dossier est déjà en instruction.'
else
dossier.passer_en_instruction!(current_instructeur) dossier.passer_en_instruction!(current_instructeur)
flash.notice = 'Dossier passé en instruction.' flash.notice = 'Dossier passé en instruction.'
rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: :en_instruction)
end end
render partial: 'state_button_refresh', locals: { dossier: dossier } render partial: 'state_button_refresh', locals: { dossier: dossier }
end end
def repasser_en_construction def repasser_en_construction
if dossier.en_construction? begin
flash.notice = 'Le dossier est déjà en construction.'
else
dossier.repasser_en_construction!(current_instructeur) dossier.repasser_en_construction!(current_instructeur)
flash.notice = 'Dossier repassé en construction.' flash.notice = 'Dossier repassé en construction.'
rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: :en_construction)
end end
render partial: 'state_button_refresh', locals: { dossier: dossier } render partial: 'state_button_refresh', locals: { dossier: dossier }
end end
def repasser_en_instruction def repasser_en_instruction
if dossier.en_instruction? begin
flash.notice = 'Le dossier est déjà en instruction.'
else
flash.notice = "Le dossier #{dossier.id} a été repassé en instruction." flash.notice = "Le dossier #{dossier.id} a été repassé en instruction."
dossier.repasser_en_instruction!(current_instructeur) dossier.repasser_en_instruction!(current_instructeur)
rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: :en_instruction)
end end
render partial: 'state_button_refresh', locals: { dossier: dossier } render partial: 'state_button_refresh', locals: { dossier: dossier }
@ -124,20 +124,23 @@ module Instructeurs
motivation = params[:dossier] && params[:dossier][:motivation] motivation = params[:dossier] && params[:dossier][:motivation]
justificatif = params[:dossier] && params[:dossier][:justificatif_motivation] justificatif = params[:dossier] && params[:dossier][:justificatif_motivation]
if dossier.termine? begin
flash.notice = "Le dossier est déjà #{dossier_display_state(dossier, lower: true)}"
else
case params[:process_action] case params[:process_action]
when "refuser" when "refuser"
target_state = :refuse
dossier.refuser!(current_instructeur, motivation, justificatif) dossier.refuser!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier considéré comme refusé." flash.notice = "Dossier considéré comme refusé."
when "classer_sans_suite" when "classer_sans_suite"
target_state = :sans_suite
dossier.classer_sans_suite!(current_instructeur, motivation, justificatif) dossier.classer_sans_suite!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier considéré comme sans suite." flash.notice = "Dossier considéré comme sans suite."
when "accepter" when "accepter"
target_state = :accepte
dossier.accepter!(current_instructeur, motivation, justificatif) dossier.accepter!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier traité avec succès." flash.notice = "Dossier traité avec succès."
end end
rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: target_state)
end end
render partial: 'state_button_refresh', locals: { dossier: dossier } render partial: 'state_button_refresh', locals: { dossier: dossier }
@ -219,5 +222,13 @@ module Instructeurs
def mark_annotations_privees_as_read def mark_annotations_privees_as_read
current_instructeur.mark_tab_as_seen(dossier, :annotations_privees) current_instructeur.mark_tab_as_seen(dossier, :annotations_privees)
end end
def aasm_error_message(exception, target_state:)
if exception.originating_state == target_state
"Le dossier est déjà #{dossier_display_state(target_state, lower: true)}."
else
"Le dossier est en ce moment #{dossier_display_state(exception.originating_state, lower: true)} : il nest pas possible de le passer #{dossier_display_state(target_state, lower: true)}."
end
end
end end
end end

View file

@ -112,9 +112,23 @@ describe Instructeurs::DossiersController, type: :controller do
context 'when the dossier has already been put en_instruction' do context 'when the dossier has already been put en_instruction' do
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
it 'warns about the error, but doesnt raise' do it 'warns about the error' do
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction))
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.body).to have_text('Le dossier est déjà en instruction.')
end
end
context 'when the dossier has already been closed' do
let(:dossier) { create(:dossier, :accepte, procedure: procedure) }
it 'doesnt change the dossier state' do
expect(dossier.reload.state).to eq(Dossier.states.fetch(:accepte))
end
it 'warns about the error' do
expect(response).to have_http_status(:ok)
expect(response.body).to have_text('Le dossier est en ce moment accepté : il nest pas possible de le passer en instruction.')
end end
end end
end end
@ -136,9 +150,10 @@ describe Instructeurs::DossiersController, type: :controller do
context 'when the dossier has already been put en_construction' do context 'when the dossier has already been put en_construction' do
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
it 'warns about the error, but doesnt raise' do it 'warns about the error' do
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction))
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.body).to have_text('Le dossier est déjà en construction.')
end end
end end
end end
@ -161,9 +176,10 @@ describe Instructeurs::DossiersController, type: :controller do
context 'when the dossier has already been put en_instruction' do context 'when the dossier has already been put en_instruction' do
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
it 'warns about the error, but doesnt raise' do it 'warns about the error' do
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction))
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.body).to have_text('Le dossier est déjà en instruction.')
end end
end end
@ -355,15 +371,18 @@ describe Instructeurs::DossiersController, type: :controller do
context 'when a dossier is already closed' do context 'when a dossier is already closed' do
let(:dossier) { create(:dossier, :accepte, procedure: procedure) } let(:dossier) { create(:dossier, :accepte, procedure: procedure) }
before { allow(dossier).to receive(:accepter!) } before { allow(dossier).to receive(:after_accepter) }
subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' } subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' }
it 'does not close it again' do it 'does not close it again' do
subject subject
expect(dossier).not_to have_received(:accepter!) expect(dossier).not_to have_received(:after_accepter)
expect(dossier.state).to eq(Dossier.states.fetch(:accepte))
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.body).to have_text('Le dossier est déjà accepté.')
end end
end end
end end