Merge pull request #9821 from colinux/en-attente-block-instruction

ETQ instructeur je ne peux pas passer en instruction un dossier en attente de correction
This commit is contained in:
Colin Darie 2023-12-13 10:02:32 +00:00 committed by GitHub
commit 715c800788
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 97 additions and 27 deletions

View file

@ -38,3 +38,4 @@
@import '@gouvfr/dsfr/dist/component/password/password.css';
@import '@gouvfr/dsfr/dist/component/accordion/accordion.css';
@import '@gouvfr/dsfr/dist/component/tab/tab.css';
@import '@gouvfr/dsfr/dist/component/tooltip/tooltip.css';

View file

@ -4,7 +4,7 @@ class ProcessStalledDeclarativeDossierJob < ApplicationJob
case dossier.procedure.declarative_with_state
when Procedure.declarative_with_states.fetch(:en_instruction)
if !dossier.en_instruction?
if !dossier.en_instruction? && dossier.may_passer_automatiquement_en_instruction?
dossier.passer_automatiquement_en_instruction!
end
when Procedure.declarative_with_states.fetch(:accepte)

View file

@ -163,7 +163,7 @@ class Dossier < ApplicationRecord
end
event :passer_en_instruction, after: :after_passer_en_instruction do
transitions from: :en_construction, to: :en_instruction
transitions from: :en_construction, to: :en_instruction, guard: :can_passer_en_instruction?
end
event :passer_automatiquement_en_instruction, after: :after_passer_automatiquement_en_instruction do
@ -564,10 +564,19 @@ class Dossier < ApplicationRecord
false
end
def can_passer_en_instruction?
return false if pending_correction?
true
end
def can_passer_automatiquement_en_instruction?
return true if declarative_triggered_at.nil? && procedure.declarative_en_instruction?
# Auto archive always passe en instruction, even if there is a pending correction
return true if procedure.auto_archive_on? && !procedure.auto_archive_on.future?
return true if procedure.sva_svr_enabled? && sva_svr_decision_triggered_at.nil? && !pending_correction?
return false if !can_passer_en_instruction?
return true if declarative_triggered_at.nil? && procedure.declarative_en_instruction?
return true if procedure.sva_svr_enabled? && sva_svr_decision_triggered_at.nil?
false
end
@ -919,8 +928,6 @@ class Dossier < ApplicationRecord
.processed_at
save!
resolve_pending_correction!
MailTemplatePresenterService.create_commentaire_for_state(self, Dossier.states.fetch(:en_instruction))
if !disable_notification
NotificationMailer.send_en_instruction_notification(self).deliver_later

View file

@ -8,6 +8,7 @@
dossier_is_followed: current_instructeur&.follow?(dossier),
close_to_expiration: dossier.close_to_expiration?,
hidden_by_administration: dossier.hidden_by_administration?,
has_pending_correction: dossier.pending_correction?,
turbo: true,
with_menu: true }

View file

@ -44,9 +44,15 @@
- if Dossier.states[:en_construction] == state
%li{ 'data-turbo': turbo ? 'true' : 'false' }
= button_to passer_en_instruction_instructeur_dossier_path(procedure_id, dossier_id), method: :post, class: 'fr-btn fr-icon-edit-line' do
Passer en instruction
= button_to passer_en_instruction_instructeur_dossier_path(procedure_id, dossier_id), method: :post, class: 'fr-btn fr-icon-edit-line',
disabled: has_pending_correction, "aria-describedby" => has_pending_correction ? "tooltip-passer-en-instruction" : nil do
= t('views.instructeurs.dossiers.passer_en_instruction')
- if has_pending_correction
%span#tooltip-passer-en-instruction.fr-tooltip.fr-placement{ role: :tooltip, "aria-hidden" => "true" }
= t('views.instructeurs.dossiers.passer_en_instruction_blocked_by_pending_correction')
- elsif Dossier.states[:en_instruction] == state && !with_menu && !sva_svr
%li{ 'data-turbo': turbo ? 'true' : 'false' }
= button_to repasser_en_construction_instructeur_dossier_path(procedure_id, dossier_id), method: :post, class: 'fr-btn fr-btn--secondary fr-icon-draft-line' do
Repasser en construction
= t('views.instructeurs.dossiers.repasser_en_construction')

View file

@ -189,6 +189,7 @@
close_to_expiration: @statut == 'expirant',
hidden_by_administration: @statut == 'supprimes_recemment',
sva_svr: @procedure.sva_svr_enabled?,
has_pending_correction: p.pending_correction?,
turbo: false,
with_menu: false }

View file

@ -105,6 +105,7 @@
close_to_expiration: nil,
hidden_by_administration: nil,
sva_svr: p.sva_svr_decision_on.present?,
has_pending_correction: p.pending_correction?,
turbo: false,
with_menu: false }

View file

@ -377,12 +377,17 @@ en:
enabled: "Add file %{dossier_id} to the selection for the bulk operation"
disabled: "Impossible to add file %{dossier_id} to the selection because it is already in a bulk operation"
personalize: Personalize
passer_en_instruction: Switch to instruction
repasser_en_construction: Revert to submitted
show_deleted_dossiers: Show deleted files
follow_file: Follow-up the file
save: Save
stop_follow: No longer follow
no_file: No file
dossier_synthesis: Summary of files
passer_en_instruction_blocked_by_pending_correction: |
It is not possible to switch to instruction while the file is awaiting correction.
If necessary, the instructor who requested the correction can delete the corresponding message.
avis:
introduction_file_explaination: "File attached to the request for advice"
search:
@ -429,7 +434,7 @@ en:
status_overview:
status_draft: draft
status_in_progress: in progress
en_construction_html: Your file is in progress. It means that <strong>you can still edit it</strong>. You will no longer be able to edit the file when the administration will switch it to "review".
en_construction_html: Your file is in progress. It means that <strong>you can still edit it</strong>. You will no longer be able to edit the file when the administration will switch it to "processing".
status_review: undergoing review
admin_review: The administration is reviewing your file. You are no longer able to edit it.
delay_title:

View file

@ -382,12 +382,16 @@ fr:
disabled: "Impossible d'ajouter le dossier %{dossier_id} à la selection car il est déjà dans un traitement de masse"
show_deleted_dossiers: Afficher les dossiers supprimés
personalize: Personnaliser
download: Télécharger un dossier
passer_en_instruction: Passer en instruction
repasser_en_construction: Repasser en construction
follow_file: Suivre le dossier
stop_follow: Ne plus suivre
save: Enregistrer
no_file: Aucun dossier
dossier_synthesis: Synthèse des dossiers
passer_en_instruction_blocked_by_pending_correction: |
Le passage en instruction est impossible tant que le dossier est en attente de correction.
Si nécessaire, linstructeur ayant demandé la correction peut supprimer le message correspondant.
avis:
introduction_file_explaination: "Fichier joint à la demande davis"
search:

View file

@ -4,13 +4,12 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:last_operation) { dossier.dossier_operation_logs.last }
subject(:perform_job) do
described_class.perform_now(dossier)
described_class.perform_now(dossier.reload)
dossier.reload
end
before do
freeze_time
perform_job
dossier.reload
end
context 'declarative en instruction' do
@ -20,6 +19,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure:) }
it {
perform_job
expect(dossier.state).to eq('en_instruction')
expect(dossier.en_instruction_at).to eq(Time.current)
expect(last_operation.operation).to eq('passer_en_instruction')
@ -29,7 +29,19 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
context 'dossier repasse en_construction' do
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure:, declarative_triggered_at: 1.day.ago) }
it { expect(dossier.state).to eq('en_construction') }
it { expect(subject.state).to eq('en_construction') }
end
context 'with pending correction' do
let!(:correction) { create(:dossier_correction, dossier:) }
it { expect(subject.state).to eq('en_construction') }
end
context 'with resolved correction' do
let!(:correction) { create(:dossier_correction, :resolved, dossier:) }
it { expect(subject.state).to eq('en_instruction') }
end
end
@ -37,6 +49,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:, en_instruction_at: 2.days.ago) }
it {
perform_job
expect(dossier.state).to eq('en_instruction')
expect(dossier.en_instruction_at).to eq(2.days.ago)
expect(dossier.processed_at).to be_nil
@ -51,6 +64,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure:) }
it {
perform_job
expect(dossier.state).to eq('accepte')
expect(dossier.en_instruction_at).to eq(Time.current)
expect(dossier.processed_at).to eq(Time.current)
@ -64,6 +78,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:, en_instruction_at: 2.days.ago) }
it {
perform_job
expect(dossier.state).to eq('en_instruction')
expect(dossier.en_instruction_at).to eq(2.days.ago)
expect(dossier.processed_at).to be_nil
@ -74,6 +89,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :brouillon) }
it {
perform_job
expect(dossier.state).to eq('brouillon')
expect(dossier.en_instruction_at).to be_nil
expect(dossier.processed_at).to be_nil
@ -85,7 +101,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
let(:dossier) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure:, as_degraded_mode: false) }
it { expect(dossier).to be_accepte }
it { expect(subject).to be_accepte }
context 'having etablissement in degraded_mode' do
let(:dossier) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure:, as_degraded_mode: true) }
@ -95,7 +111,7 @@ RSpec.describe ProcessStalledDeclarativeDossierJob, type: :job do
expect(Sentry).to_not receive(:capture_exception)
end
it { expect(dossier).to be_en_construction }
it { expect(subject).to be_en_construction }
end
end
end

View file

@ -1148,7 +1148,6 @@ describe Dossier, type: :model do
let(:last_operation) { dossier.dossier_operation_logs.last }
let(:operation_serialized) { last_operation.data }
let(:instructeur) { create(:instructeur) }
let!(:correction) { create(:dossier_correction, dossier:) } # correction has a commentaire
subject(:passer_en_instruction) { dossier.passer_en_instruction!(instructeur: instructeur) }
@ -1167,13 +1166,6 @@ describe Dossier, type: :model do
it { expect { passer_en_instruction }.to change { dossier.commentaires.count }.by(1) }
it "resolve pending correction" do
passer_en_instruction
expect(dossier.pending_correction?).to be_falsey
expect(correction.reload.resolved_at).to be_present
end
it 'creates a commentaire in the messagerie with expected wording' do
passer_en_instruction
@ -1253,6 +1245,24 @@ describe Dossier, type: :model do
end
end
describe '#can_passer_en_instruction?' do
let(:dossier) { create(:dossier, :en_construction) }
it { expect(dossier.can_passer_en_instruction?).to be_truthy }
context 'when there is a pending correction' do
before { create(:dossier_correction, dossier:) }
it { expect(dossier.can_passer_en_instruction?).to be_falsey }
end
context 'when there is a resolved correction' do
before { create(:dossier_correction, :resolved, dossier:) }
it { expect(dossier.can_passer_en_instruction?).to be_truthy }
end
end
describe '#can_passer_automatiquement_en_instruction?' do
let(:dossier) { create(:dossier, :en_construction, declarative_triggered_at: declarative_triggered_at) }
let(:declarative_triggered_at) { nil }
@ -1289,6 +1299,15 @@ describe Dossier, type: :model do
it { expect(dossier.can_passer_automatiquement_en_instruction?).to be_truthy }
end
context 'when there are pending correction' do
before { create(:dossier_correction, dossier:) }
it "passes en instruction and keep the correction request" do
expect(dossier.can_passer_automatiquement_en_instruction?).to be_truthy
expect(dossier.pending_correction?).to be_truthy
end
end
end
context 'when procedure has sva or svr enabled' do
@ -2178,7 +2197,7 @@ describe Dossier, type: :model do
let!(:type_de_champ_2) { create(:type_de_champ_textarea, procedure: procedure) }
let(:stable_ids) { [type_de_champ_1.stable_id, type_de_champ_2.stable_id] }
it { expect(subject).to match(dossier.champs_public.joins(:type_de_champ).where(types_de_champ: { stable_id: stable_ids })) }
it { expect(subject).to match_array(dossier.champs_public.joins(:type_de_champ).where(types_de_champ: { stable_id: stable_ids })) }
end
end
end

View file

@ -56,7 +56,7 @@ describe 'instructeurs/dossiers/show', type: :view do
let(:dossier) { create(:dossier, :en_construction) }
it 'displays the correct actions' do
within("form[action=\"#{passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier)}\"]") do
expect(subject).to have_button('Passer en instruction')
expect(subject).to have_button('Passer en instruction', disabled: false)
end
within("form[action=\"#{follow_instructeur_dossier_path(dossier.procedure, dossier)}\"]") do
expect(subject).to have_button('Suivre le dossier')
@ -64,6 +64,15 @@ describe 'instructeurs/dossiers/show', type: :view do
expect(subject).to have_button('Demander une correction')
expect(subject).to have_selector('.header-actions ul:first-child > li.instruction-button', count: 1)
end
context 'with pending correction' do
before { create(:dossier_correction, dossier:) }
it 'disable the instruction button' do
expect(subject).to have_button('Passer en instruction', disabled: true)
expect(subject).to have_content('Le passage en instruction est impossible')
end
end
end
context 'en_instruction' do