From b5e2c9b860c121532fa25854e7bcddb022c1ebb6 Mon Sep 17 00:00:00 2001 From: Colin Darie <colin@darie.eu> Date: Mon, 4 Sep 2023 15:14:50 +0200 Subject: [PATCH] fix(sva): improvements when a dossier has already been terminated --- .../sva_svr_decision_badge_component.rb | 32 ++++++-- .../sva_svr_decision_badge_component.en.yml | 7 +- .../sva_svr_decision_badge_component.fr.yml | 7 +- ...sva_svr_decision_badge_component.html.haml | 25 ++++--- app/models/dossier.rb | 5 ++ .../sva_svr_decision_badge_component_spec.rb | 75 +++++++++++++++++++ spec/models/dossier_spec.rb | 3 +- 7 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 spec/components/instructeurs/sva_svr_decision_badge_component_spec.rb diff --git a/app/components/instructeurs/sva_svr_decision_badge_component.rb b/app/components/instructeurs/sva_svr_decision_badge_component.rb index cd0aef7e4..afc647749 100644 --- a/app/components/instructeurs/sva_svr_decision_badge_component.rb +++ b/app/components/instructeurs/sva_svr_decision_badge_component.rb @@ -26,11 +26,13 @@ class Instructeurs::SVASVRDecisionBadgeComponent < ApplicationComponent class_names( 'fr-badge fr-badge--sm': true, 'fr-badge--warning': soon?, - 'fr-badge--info': !soon? + 'fr-badge--info': !without_date? && !soon? ) end def soon? + return false if object.sva_svr_decision_on.nil? + object.sva_svr_decision_on < 7.days.from_now.to_date end @@ -51,16 +53,36 @@ class Instructeurs::SVASVRDecisionBadgeComponent < ApplicationComponent end def label_for_badge - sva? ? "SVA :" : "SVR :" + "#{human_decision} : " end def title - return if without_date? - - if pending_correction? + if previously_termine? + t('.previously_termine_title') + elsif depose_before_configuration? + t('.depose_before_configuration_title', decision: human_decision) + elsif without_date? + t('.manual_decision_title', decision: human_decision) + elsif pending_correction? t(".dossier_terminated_x_days_after_correction", count: days_count) else t(".dossier_terminated_on", date: helpers.l(object.sva_svr_decision_on)) end end + + def human_decision + procedure.sva_svr_configuration.human_decision + end + + def previously_termine? + return if !object.respond_to?(:previously_termine?) + + object.previously_termine? + end + + def depose_before_configuration? + return if !object.respond_to?(:sva_svr_decision_triggered_at) + + object.sva_svr_decision_on.nil? && object.sva_svr_decision_triggered_at.nil? + end end diff --git a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.en.yml b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.en.yml index 54bfb9bae..beb76ff7a 100644 --- a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.en.yml +++ b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.en.yml @@ -1,7 +1,10 @@ --- en: - no_sva: Submitted before SVA - no_svr: Submitted before SVR + manual_decision: Manual instruction + manual_decision_title: The file must be processed by an instructor, either because it was submitted before the %{decision} configuration, or because it has been returned to the instruction stage. + depose_before_configuration: Submitted before %{decision} + depose_before_configuration_title: This file was submitted before the %{decision} configuration. + previously_termine_title: The file has been returned to the instruction stage. It must now be processed by an instructor. in_days: zero: Today one: Tomorrow diff --git a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.fr.yml b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.fr.yml index b06a63f49..6aa17c73a 100644 --- a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.fr.yml +++ b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.fr.yml @@ -1,7 +1,10 @@ --- fr: - no_sva: Déposé avant SVA - no_svr: Déposé avant SVR + manual_decision: Instruction manuelle + manual_decision_title: Le dossier doit être traité par un instructeur, soit car il a été déposé avant la configuration %{decision}, soit car il a été repassé en instruction. + depose_before_configuration: Déposé avant %{decision} + depose_before_configuration_title: Ce dossier a été déposé avant la configuration %{decision}. + previously_termine_title: Le dossier a été repassé en instruction. Il doit être traité par un instructeur. in_days: zero: Aujourd’hui one: Demain diff --git a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.html.haml b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.html.haml index 0dcfcfa34..617ba4554 100644 --- a/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.html.haml +++ b/app/components/instructeurs/sva_svr_decision_badge_component/sva_svr_decision_badge_component.html.haml @@ -1,11 +1,14 @@ -- if without_date? - %span.fr-badge.fr-badge--sm - = t(sva? ? '.no_sva' : '.no_svr') -- else - %span{ class: classes, title: title } - - if with_label.present? - = label_for_badge - - if pending_correction? - = t('.remaining_days_after_correction', count: days_count) - - else - = t('.in_days', count: days_count) +%span{ class: classes, title: title } + - if with_label.present? + = label_for_badge + + - if previously_termine? + = t('.manual_decision') + - elsif depose_before_configuration? + = t('.depose_before_configuration', decision: human_decision) + - elsif without_date? # generic case without SVA/SVR date, when we have a projection + = t('.manual_decision') + - elsif pending_correction? + = t('.remaining_days_after_correction', count: days_count) + - else + = t('.in_days', count: days_count) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index ad918b743..9baa5928f 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -942,6 +942,7 @@ class Dossier < ApplicationRecord .processed_at attestation&.destroy + self.sva_svr_decision_on = nil self.motivation = nil self.justificatif_motivation.purge_later @@ -1089,6 +1090,10 @@ class Dossier < ApplicationRecord end end + def previously_termine? + traitements.termine.exists? + end + def remove_titres_identite! champs_public.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later) end diff --git a/spec/components/instructeurs/sva_svr_decision_badge_component_spec.rb b/spec/components/instructeurs/sva_svr_decision_badge_component_spec.rb new file mode 100644 index 000000000..357ff17ba --- /dev/null +++ b/spec/components/instructeurs/sva_svr_decision_badge_component_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +RSpec.describe Instructeurs::SVASVRDecisionBadgeComponent, type: :component do + let(:procedure) { create(:procedure, sva_svr: { decision: :sva, period: 10, unit: :days, resume: :continue }) } + let(:with_label) { false } + + before do + travel_to DateTime.new(2023, 9, 1) + end + + context 'with dossier object' do + subject do + render_inline(described_class.new(projection_or_dossier: dossier, procedure:, with_label:)) + end + + let(:title) { subject.at_css("span")["title"] } + + context 'dossier en instruction' do + let(:dossier) { create(:dossier, :en_instruction, procedure:, sva_svr_decision_on: Date.new(2023, 9, 5)) } + it { expect(subject).to have_text("dans 4 jours") } + it { expect(title).to have_text("sera automatiquement traité le 05/09/2023") } + + context 'with label' do + let(:with_label) { true } + it { expect(subject.text.delete("\n")).to have_text("SVA : dans 4 jours") } + end + end + + context 'without sva date' do + let(:dossier) { create(:dossier, :en_instruction, procedure:) } + + context 'dossier depose before configuration' do + it { expect(subject).to have_text("Déposé avant SVA") } + it { expect(title).to have_text("avant la configuration SVA") } + end + + context 'dossier previously terminated' do + before { + create(:traitement, :accepte, dossier:) + } + + it { expect(subject).to have_text("Instruction manuelle") } + it { expect(title).to have_text("repassé en instruction") } + end + end + + context 'pending corrections' do + let(:dossier) { create(:dossier, :en_construction, procedure:, depose_at: Time.current, sva_svr_decision_on: Date.new(2023, 9, 5)) } + + before do + create(:dossier_correction, dossier:) + end + + it { expect(subject).to have_text("4 j. après correction") } + end + end + + context 'with projection object' do + subject do + render_inline(described_class.new(projection_or_dossier: projection, procedure:, with_label:)) + end + + context 'dossier en instruction' do + let(:projection) { DossierProjectionService::DossierProjection.new(dossier_id: 12, state: :en_instruction, sva_svr_decision_on: Date.new(2023, 9, 5)) } + + it { expect(subject).to have_text("dans 4 jours") } + end + + context 'dossier without sva decision date' do + let(:projection) { DossierProjectionService::DossierProjection.new(dossier_id: 12, state: :en_instruction) } + + it { expect(subject).to have_text("Instruction manuelle") } + end + end +end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 9080e54d3..0e8c92bd5 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -1494,7 +1494,7 @@ describe Dossier, type: :model do end describe '#repasser_en_instruction!' do - let(:dossier) { create(:dossier, :refuse, :with_attestation, :with_justificatif, archived: true, termine_close_to_expiration_notice_sent_at: Time.zone.now) } + let(:dossier) { create(:dossier, :refuse, :with_attestation, :with_justificatif, archived: true, termine_close_to_expiration_notice_sent_at: Time.zone.now, sva_svr_decision_on: 1.day.ago) } let!(:instructeur) { create(:instructeur) } let(:last_operation) { dossier.dossier_operation_logs.last } @@ -1512,6 +1512,7 @@ describe Dossier, type: :model do it { expect(dossier.motivation).to be_nil } it { expect(dossier.justificatif_motivation.attached?).to be_falsey } it { expect(dossier.attestation).to be_nil } + it { expect(dossier.sva_svr_decision_on).to be_nil } it { expect(dossier.termine_close_to_expiration_notice_sent_at).to be_nil } it { expect(last_operation.operation).to eq('repasser_en_instruction') } it { expect(last_operation.data['author']['email']).to eq(instructeur.email) }