From 4bdd4310ab70db11fea057ba06e49a9d48cba773 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Mon, 5 Jun 2023 18:53:03 +0200 Subject: [PATCH] feat(sva): calculcate decision date with corrections delays & resume methods --- app/models/dossier.rb | 2 +- .../sva_svr_date_calculator_service.rb | 23 ---- ...va_svr_decision_date_calculator_service.rb | 56 +++++++++ .../sva_svr_date_calculator_service_spec.rb | 34 ----- ...r_decision_date_calculator_service_spec.rb | 118 ++++++++++++++++++ 5 files changed, 175 insertions(+), 58 deletions(-) delete mode 100644 app/services/sva_svr_date_calculator_service.rb create mode 100644 app/services/sva_svr_decision_date_calculator_service.rb delete mode 100644 spec/services/sva_svr_date_calculator_service_spec.rb create mode 100644 spec/services/sva_svr_decision_date_calculator_service_spec.rb diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 78ecbf87a..ef7d5fbcd 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -1070,7 +1070,7 @@ class Dossier < ApplicationRecord return unless procedure.sva_svr_enabled? return if sva_svr_decision_triggered_at.present? - self.sva_svr_decision_on = SVASVRDateCalculatorService.new(self, procedure).calculate + self.sva_svr_decision_on = SVASVRDecisionDateCalculatorService.new(self, procedure).decision_date if en_construction? && may_passer_automatiquement_en_instruction? passer_automatiquement_en_instruction! diff --git a/app/services/sva_svr_date_calculator_service.rb b/app/services/sva_svr_date_calculator_service.rb deleted file mode 100644 index d66bd242b..000000000 --- a/app/services/sva_svr_date_calculator_service.rb +++ /dev/null @@ -1,23 +0,0 @@ -class SVASVRDateCalculatorService - attr_reader :dossier, :procedure - - def initialize(dossier, procedure) - @dossier = dossier - @procedure = procedure - end - - def calculate - config = procedure.sva_svr_configuration - unit = config.unit.to_sym - period = config.period.to_i - - case unit - when :days - dossier.depose_at.to_date + period.days - when :weeks - dossier.depose_at.to_date + period.weeks - when :months - dossier.depose_at.to_date + period.months - end - end -end diff --git a/app/services/sva_svr_decision_date_calculator_service.rb b/app/services/sva_svr_decision_date_calculator_service.rb new file mode 100644 index 000000000..6ddd6cbb3 --- /dev/null +++ b/app/services/sva_svr_decision_date_calculator_service.rb @@ -0,0 +1,56 @@ +class SVASVRDecisionDateCalculatorService + attr_reader :dossier, :procedure, :unit, :period, :resume_method + + def initialize(dossier, procedure) + @dossier = dossier + @procedure = procedure + + config = procedure.sva_svr_configuration + @unit = config.unit.to_sym + @period = config.period.to_i + @resume_method = config.resume.to_sym + end + + def decision_date + base_date = determine_base_date + + duration = case unit + when :days + period.days + when :weeks + period.weeks + when :months + period.months + end + + base_date + duration + end + + private + + def determine_base_date + return dossier.depose_at.to_date + total_correction_delay if resume_method == :continue + + if dossier.corrections.any? + most_recent_correction_date + else + dossier.depose_at.to_date + end + end + + def total_correction_delay + dossier.corrections.sum do |correction| + # If the correction is not resolved, we use the current date + # so interfaces could calculate how many remaining days + resolved_date = correction.resolved_at&.to_date || Date.current + + (resolved_date - correction.created_at.to_date).days + end + end + + def most_recent_correction_date + return Date.current if dossier.pending_correction? + + dossier.corrections.max_by(&:resolved_at).resolved_at.to_date + end +end diff --git a/spec/services/sva_svr_date_calculator_service_spec.rb b/spec/services/sva_svr_date_calculator_service_spec.rb deleted file mode 100644 index 1d8dcc2f9..000000000 --- a/spec/services/sva_svr_date_calculator_service_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'rails_helper' - -describe SVASVRDateCalculatorService do - let(:procedure) { create(:procedure, sva_svr: config) } - let(:dossier) { create(:dossier, :en_instruction, procedure:, depose_at: DateTime.new(2023, 5, 15, 12)) } - - subject { described_class.new(dossier, procedure).calculate } - - describe '#calculate' do - context 'when sva has a months period' do - let(:config) { { decision: :sva, period: 2, unit: :months, resume: :continue } } - - it 'calculates the date based on SVA rules' do - expect(subject).to eq(Date.new(2023, 7, 15)) - end - end - - context 'when sva has a days period' do - let(:config) { { decision: :sva, period: 30, unit: :days, resume: :continue } } - - it 'calculates the date based on SVA rules' do - expect(subject).to eq(Date.new(2023, 6, 14)) - end - end - - context 'when sva has a weeks period' do - let(:config) { { decision: :sva, period: 8, unit: :weeks, resume: :continue } } - - it 'calculates the date based on SVA rules' do - expect(subject).to eq(Date.new(2023, 7, 10)) - end - end - end -end diff --git a/spec/services/sva_svr_decision_date_calculator_service_spec.rb b/spec/services/sva_svr_decision_date_calculator_service_spec.rb new file mode 100644 index 000000000..cd3de51c5 --- /dev/null +++ b/spec/services/sva_svr_decision_date_calculator_service_spec.rb @@ -0,0 +1,118 @@ +require 'rails_helper' + +describe SVASVRDecisionDateCalculatorService do + include ActiveSupport::Testing::TimeHelpers + + let(:procedure) { create(:procedure, sva_svr: config) } + let(:dossier) { create(:dossier, :en_instruction, procedure:, depose_at: DateTime.new(2023, 5, 15, 12)) } + + subject { described_class.new(dossier, procedure).decision_date } + + describe '#decision_date' do + context 'when sva has a months period' do + let(:config) { { decision: :sva, period: 2, unit: :months, resume: :continue } } + + it 'calculates the date based on SVA rules' do + expect(subject).to eq(Date.new(2023, 7, 15)) + end + end + + context 'when sva has a days period' do + let(:config) { { decision: :sva, period: 30, unit: :days, resume: :continue } } + + it 'calculates the date based on SVA rules' do + expect(subject).to eq(Date.new(2023, 6, 14)) + end + end + + context 'when sva has a weeks period' do + let(:config) { { decision: :sva, period: 8, unit: :weeks, resume: :continue } } + + it 'calculates the date based on SVA rules' do + expect(subject).to eq(Date.new(2023, 7, 10)) + end + end + + context 'when sva resume setting is continue' do + let(:config) { { decision: :sva, period: 2, unit: :months, resume: :continue } } + + context 'when a dossier is corrected and resolved' do + let!(:correction) do + created_at = DateTime.new(2023, 5, 20, 15) + resolved_at = DateTime.new(2023, 5, 25, 12) + create(:dossier_correction, dossier:, created_at:, resolved_at:) + end + + it 'calculates the date based on SVA rules with correction delay' do + expect(subject).to eq(Date.new(2023, 7, 20)) + end + + context 'when there are multiple corrections' do + let!(:correction2) do + created_at = DateTime.new(2023, 5, 30, 18) + resolved_at = DateTime.new(2023, 6, 3, 8) + create(:dossier_correction, dossier:, created_at:, resolved_at:) + end + + it 'calculates the date based on SVA rules with all correction delays' do + expect(subject).to eq(Date.new(2023, 7, 24)) + end + end + + context 'there is a pending correction' do + before do + travel_to DateTime.new(2023, 5, 30, 18) do + dossier.flag_as_pending_correction!(build(:commentaire, dossier:)) + end + + travel_to DateTime.new(2023, 6, 5, 8) # 6 days elapsed + end + + it 'calculates the date, like if resolution will be today' do + expect(subject).to eq(Date.new(2023, 7, 26)) + end + end + end + end + + context 'when sva resume setting is reset' do + let(:config) { { decision: :sva, period: 2, unit: :months, resume: :reset } } + + context 'there is no correction' do + it 'calculates the date based on deposed_at' do + expect(subject).to eq(Date.new(2023, 7, 15)) + end + end + + context 'there are multiple resolved correction' do + before do + created_at = DateTime.new(2023, 5, 16, 15) + resolved_at = DateTime.new(2023, 5, 17, 12) + create(:dossier_correction, dossier:, created_at:, resolved_at:) + + created_at = DateTime.new(2023, 5, 20, 15) + resolved_at = DateTime.new(2023, 5, 25, 12) + create(:dossier_correction, dossier:, created_at:, resolved_at:) + end + + it 'calculates the date based on SVA rules from the last resolved date' do + expect(subject).to eq(Date.new(2023, 7, 25)) + end + end + + context 'there is a pending correction' do + before do + travel_to DateTime.new(2023, 5, 30, 18) do + dossier.flag_as_pending_correction!(build(:commentaire, dossier:)) + end + + travel_to DateTime.new(2023, 6, 5, 8) + end + + it 'calculates the date, like if resolution will be today and delay restarted' do + expect(subject).to eq(Date.new(2023, 8, 5)) + end + end + end + end +end