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) }