From ed4d5cb36a042715820ecaf48a92676db510b8d8 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Fri, 2 Dec 2022 18:15:43 +0100 Subject: [PATCH] refactor(demarche): make declarative demarche processing syncroneous --- app/controllers/users/dossiers_controller.rb | 1 + app/jobs/cron/declarative_procedures_job.rb | 13 -- app/models/dossier.rb | 20 ++- app/models/procedure.rb | 21 +-- .../cron/declarative_procedures_job_spec.rb | 124 ------------------ spec/models/instructeur_spec.rb | 29 ++-- spec/services/notification_service_spec.rb | 15 +-- 7 files changed, 42 insertions(+), 181 deletions(-) delete mode 100644 app/jobs/cron/declarative_procedures_job.rb delete mode 100644 spec/jobs/cron/declarative_procedures_job_spec.rb diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 031f81fbc..237f347aa 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -165,6 +165,7 @@ module Users if errors.blank? @dossier.passer_en_construction! + @dossier.process_declarative! NotificationMailer.send_en_construction_notification(@dossier).deliver_later @dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur| DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later diff --git a/app/jobs/cron/declarative_procedures_job.rb b/app/jobs/cron/declarative_procedures_job.rb deleted file mode 100644 index 643ba7f06..000000000 --- a/app/jobs/cron/declarative_procedures_job.rb +++ /dev/null @@ -1,13 +0,0 @@ -class Cron::DeclarativeProceduresJob < Cron::CronJob - self.schedule_expression = "every 1 minute" - - def perform(*args) - Procedure.declarative.find_each do |procedure| - begin - procedure.process_dossiers! - rescue => e - Sentry.capture_exception(e) - end - end - end -end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 8ebaef95f..403c2d079 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -169,7 +169,7 @@ class Dossier < ApplicationRecord end event :passer_automatiquement_en_instruction, after: :after_passer_automatiquement_en_instruction do - transitions from: :en_construction, to: :en_instruction + transitions from: :en_construction, to: :en_instruction, guard: :can_passer_automatiquement_en_instruction? end event :repasser_en_construction, after: :after_repasser_en_construction do @@ -181,7 +181,7 @@ class Dossier < ApplicationRecord end event :accepter_automatiquement, after: :after_accepter_automatiquement do - transitions from: :en_construction, to: :accepte, guard: :can_terminer? + transitions from: :en_construction, to: :accepte, guard: :can_accepter_automatiquement? end event :refuser, after: :after_refuser do @@ -526,6 +526,14 @@ class Dossier < ApplicationRecord true end + def can_accepter_automatiquement? + declarative_triggered_at.nil? && can_terminer? + end + + def can_passer_automatiquement_en_instruction? + declarative_triggered_at.nil? + end + def can_repasser_en_instruction? termine? && !user_deleted? end @@ -978,6 +986,14 @@ class Dossier < ApplicationRecord log_dossier_operation(instructeur, :classer_sans_suite, self) end + def process_declarative! + if procedure.declarative_accepte? && may_accepter_automatiquement? + accepter_automatiquement! + elsif procedure.declarative_en_instruction? && may_passer_automatiquement_en_instruction? + passer_automatiquement_en_instruction! + end + end + def remove_titres_identite! champs_public.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later) end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 3c60da741..da98e1e4b 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -447,6 +447,10 @@ class Procedure < ApplicationRecord declarative_with_state == Procedure.declarative_with_states.fetch(:accepte) end + def declarative_en_instruction? + declarative_with_state == Procedure.declarative_with_states.fetch(:en_instruction) + end + def self.declarative_attributes_for_select declarative_with_states.map do |state, _| [I18n.t("activerecord.attributes.#{model_name.i18n_key}.declarative_with_state/#{state}"), state] @@ -635,23 +639,6 @@ class Procedure < ApplicationRecord result end - def process_dossiers! - case declarative_with_state - when Procedure.declarative_with_states.fetch(:en_instruction) - dossiers - .state_en_construction - .where(declarative_triggered_at: nil) - .find_each(&:passer_automatiquement_en_instruction!) - when Procedure.declarative_with_states.fetch(:accepte) - dossiers - .state_en_construction - .where(declarative_triggered_at: nil) - .find_each do |dossier| - dossier.accepter_automatiquement! if dossier.may_accepter_automatiquement? - end - end - end - def logo_url if logo.attached? Rails.application.routes.url_helpers.url_for(logo) diff --git a/spec/jobs/cron/declarative_procedures_job_spec.rb b/spec/jobs/cron/declarative_procedures_job_spec.rb deleted file mode 100644 index c1bc64f30..000000000 --- a/spec/jobs/cron/declarative_procedures_job_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -RSpec.describe Cron::DeclarativeProceduresJob, type: :job do - describe "perform" do - let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) } - let(:instruction_date) { date + 120 } - - let(:state) { nil } - let(:procedure) { create(:procedure, :published, :for_individual, :with_instructeur, declarative_with_state: state) } - let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) } - let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) } - let(:dossier_recu) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) } - let(:dossier_brouillon) { create(:dossier, procedure: procedure) } - let(:dossier_repasse_en_construction) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } - - before do - Timecop.freeze(date) - dossier_repasse_en_construction&.touch(:declarative_triggered_at) - end - - subject(:perform_job) do - dossiers = [ - nouveau_dossier1, - nouveau_dossier2, - dossier_recu, - dossier_brouillon, - dossier_repasse_en_construction - ].compact - - Cron::DeclarativeProceduresJob.new.perform - - dossiers.each(&:reload) - end - - after { Timecop.return } - - context "with some dossiers" do - context "en_construction" do - let(:state) { Dossier.states.fetch(:en_instruction) } - let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last } - - it { - perform_job - expect(nouveau_dossier1.en_instruction?).to be_truthy - expect(nouveau_dossier1.en_instruction_at).to eq(date) - expect(last_operation.operation).to eq('passer_en_instruction') - expect(last_operation.automatic_operation?).to be_truthy - - expect(nouveau_dossier2.en_instruction?).to be_truthy - expect(nouveau_dossier2.en_instruction_at).to eq(date) - - expect(dossier_recu.en_instruction?).to be_truthy - expect(dossier_recu.en_instruction_at).to eq(instruction_date) - - expect(dossier_brouillon.brouillon?).to be_truthy - expect(dossier_brouillon.en_instruction_at).to eq(nil) - - expect(dossier_repasse_en_construction.en_construction?).to be_truthy - } - end - - context "accepte" do - let(:state) { Dossier.states.fetch(:accepte) } - let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last } - - it { - perform_job - expect(nouveau_dossier1.accepte?).to be true - expect(nouveau_dossier1.en_instruction_at).to eq(date) - expect(nouveau_dossier1.processed_at).to eq(date) - expect(nouveau_dossier1.attestation).to be_present - expect(last_operation.operation).to eq('accepter') - expect(last_operation.automatic_operation?).to be_truthy - - expect(nouveau_dossier2.accepte?).to be true - expect(nouveau_dossier2.en_instruction_at).to eq(date) - expect(nouveau_dossier2.processed_at).to eq(date) - expect(nouveau_dossier2.attestation).to be_present - - expect(dossier_recu.en_instruction?).to be true - expect(dossier_recu.en_instruction_at).to eq(instruction_date) - expect(dossier_recu.processed_at).to eq(nil) - - expect(dossier_brouillon.brouillon?).to be true - expect(dossier_brouillon.en_instruction_at).to eq(nil) - expect(dossier_brouillon.processed_at).to eq(nil) - } - - context "having etablissement in degraded_mode" do - let(:procedure) { create(:procedure, :published, :with_instructeur, for_individual: false, declarative_with_state: state) } - let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: false) } - let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: true) } - let(:dossier_recu) { nil } - let(:dossier_repasse_en_construction) { nil } - - before do - expect(nouveau_dossier2).to_not receive(:accepter_automatiquement) - expect(Sentry).to_not receive(:capture_exception) - end - - it { - perform_job - expect(nouveau_dossier1).to be_accepte - expect(nouveau_dossier2).to be_en_construction - } - end - end - end - end - - describe 'safer perform' do - let(:state) { Dossier.states.fetch(:en_instruction) } - - it 'works no matter if one raise' do - procedure_1 = instance_double("Procedure") - expect(procedure_1).to receive(:process_dossiers!) - procedure_2 = instance_double("Procedure") - expect(procedure_2).to receive(:process_dossiers!).and_raise("boom") - procedure_3 = double(process_dossiers!: true) - expect(procedure_3).to receive(:process_dossiers!) - - expect(Procedure).to receive_message_chain(:declarative, :find_each).and_yield(procedure_1).and_yield(procedure_2).and_yield(procedure_3) - Cron::DeclarativeProceduresJob.perform_now - end - end -end diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index a587027e2..ff6220e57 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -186,7 +186,7 @@ describe Instructeur, type: :model do end describe '#notifications_for_dossier' do - let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier) { create(:dossier, :en_construction, :followed) } let(:instructeur) { dossier.follows.first.instructeur } subject { instructeur.notifications_for_dossier(dossier) } @@ -245,12 +245,12 @@ describe Instructeur, type: :model do # a procedure, one group, 2 instructeurs let(:procedure) { create(:simple_procedure, :routee, :with_type_de_champ_private, :for_individual) } let(:gi_p1) { procedure.groupe_instructeurs.last } - let!(:dossier) { create(:dossier, :with_individual, :followed, procedure: procedure, groupe_instructeur: gi_p1, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier) { create(:dossier, :en_construction, :with_individual, :followed, procedure: procedure, groupe_instructeur: gi_p1) } let(:instructeur) { dossier.follows.first.instructeur } let!(:instructeur_2) { create(:instructeur, groupe_instructeurs: [gi_p1]) } # another procedure, dossier followed by a third instructeur - let!(:dossier_on_procedure_2) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier_on_procedure_2) { create(:dossier, :en_construction, :followed) } let!(:instructeur_on_procedure_2) { dossier_on_procedure_2.follows.first.instructeur } let(:gi_p2) { dossier.groupe_instructeur } @@ -355,7 +355,7 @@ describe Instructeur, type: :model do end describe '#procedure_ids_with_notifications' do - let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier) { create(:dossier, :en_construction, :followed) } let(:instructeur) { dossier.follows.first.instructeur } let(:procedure) { dossier.procedure } @@ -369,7 +369,7 @@ describe Instructeur, type: :model do end describe '#mark_tab_as_seen' do - let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier) { create(:dossier, :en_construction, :followed) } let(:instructeur) { dossier.follows.first.instructeur } let(:freeze_date) { Time.zone.parse('12/12/2012') } @@ -416,7 +416,7 @@ describe Instructeur, type: :model do end context 'when a dossier in construction exists' do - let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) } + let!(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) } it do expect(instructeur.email_notification_data).to eq([ @@ -454,12 +454,11 @@ describe Instructeur, type: :model do end context 'when a declarated dossier in instruction exists' do - let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) } before do - procedure_to_assign.update(declarative_with_state: "en_instruction") - Cron::DeclarativeProceduresJob.new.perform - dossier.reload + procedure_to_assign.update!(declarative_with_state: "en_instruction") + dossier.process_declarative! end it { expect(procedure_to_assign.declarative_with_state).to eq("en_instruction") } @@ -479,12 +478,11 @@ describe Instructeur, type: :model do end context 'when a declarated dossier in accepte processed at today exists' do - let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) } before do procedure_to_assign.update(declarative_with_state: "accepte") - Cron::DeclarativeProceduresJob.new.perform - dossier.reload + dossier.process_declarative! end it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") } @@ -496,13 +494,12 @@ describe Instructeur, type: :model do end context 'when a declarated dossier in accepte processed at yesterday exists' do - let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) } before do procedure_to_assign.update(declarative_with_state: "accepte") - Cron::DeclarativeProceduresJob.new.perform + dossier.process_declarative! dossier.traitements.last.update(processed_at: Time.zone.yesterday.beginning_of_day) - dossier.reload end it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") } diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 15e146e9e..bf641edd5 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -48,11 +48,10 @@ describe NotificationService do end context 'when a declarative dossier in instruction exists on this procedure' do - let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "en_instruction") - Cron::DeclarativeProceduresJob.new.perform - dossier.reload + dossier.process_declarative! end it do @@ -62,12 +61,11 @@ describe NotificationService do end context 'when a declarative dossier in accepte on yesterday exists on this procedure' do - let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "accepte") - Cron::DeclarativeProceduresJob.new.perform + dossier.process_declarative! dossier.traitements.last.update!(processed_at: Time.zone.yesterday.beginning_of_day) - dossier.reload end it do @@ -77,11 +75,10 @@ describe NotificationService do end context 'when a declarative dossier in accepte on today exists on this procedure' do - let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } + let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "accepte") - Cron::DeclarativeProceduresJob.new.perform - dossier.reload + dossier.process_declarative! end it do