diff --git a/app/jobs/cron/empty_dossiers_brouillon_deletion_job.rb b/app/jobs/cron/empty_dossiers_brouillon_deletion_job.rb deleted file mode 100644 index a39f38b3597..00000000000 --- a/app/jobs/cron/empty_dossiers_brouillon_deletion_job.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -class Cron::EmptyDossiersBrouillonDeletionJob < Cron::CronJob - self.schedule_expression = Expired.schedule_at(self) - - def self.deletion_window - 3.weeks.ago..2.weeks.ago - end - - def perform(*args) - Expired::DossiersDeletionService.new.process_empty_dossiers_brouillon(deletion_window) - end -end diff --git a/app/jobs/cron/never_touched_dossiers_brouillon_deletion_job.rb b/app/jobs/cron/never_touched_dossiers_brouillon_deletion_job.rb new file mode 100644 index 00000000000..24a8d4ce241 --- /dev/null +++ b/app/jobs/cron/never_touched_dossiers_brouillon_deletion_job.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Cron::NeverTouchedDossiersBrouillonDeletionJob < Cron::CronJob + self.schedule_expression = Expired.schedule_at(self) + + def perform(*args) + Expired::DossiersDeletionService.new.process_never_touched_dossiers_brouillon + end +end diff --git a/app/models/concerns/dossier_empty_concern.rb b/app/models/concerns/dossier_empty_concern.rb deleted file mode 100644 index af2acbbabfc..00000000000 --- a/app/models/concerns/dossier_empty_concern.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module DossierEmptyConcern - extend ActiveSupport::Concern - - included do - scope :empty_brouillon, -> (created_at) do - dossiers_ids = Dossier.brouillon.where(created_at:).ids - - dossiers_with_value = Dossier.select('id').includes(:champs) - .where.not(champs: { value: nil }) - .where(id: dossiers_ids) - - dossier_with_geo_areas = Dossier.select('id').includes(champs: :geo_areas) - .where.not(geo_areas: { id: nil }) - .where(id: dossiers_ids) - - dossier_with_pj = Dossier.select('id') - .joins(champs: :piece_justificative_file_attachments) - .where(id: dossiers_ids) - - brouillon - .where.not(id: dossiers_with_value) - .where.not(id: dossier_with_geo_areas) - .where.not(id: dossier_with_pj) - .where(id: dossiers_ids) - end - end -end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 677ea9a4ee9..35b5174436f 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -12,7 +12,6 @@ class Dossier < ApplicationRecord include DossierSectionsConcern include DossierStateConcern include DossierChampsConcern - include DossierEmptyConcern include DossierExportConcern enum :state, { @@ -327,6 +326,7 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon end end + scope :never_touched_brouillon_expired, -> { brouillon.where(last_champ_updated_at: nil, last_champ_piece_jointe_updated_at: nil).where(created_at: ..2.weeks.ago) } scope :brouillon_expired, -> do state_brouillon .visible_by_user diff --git a/app/services/expired.rb b/app/services/expired.rb index ce9948da532..afc41bae978 100644 --- a/app/services/expired.rb +++ b/app/services/expired.rb @@ -25,7 +25,7 @@ module Expired # it send a lot o email, so we spread our jobs through the day def self.schedule_at(caller) case caller.name - when 'Cron::EmptyDossiersBrouillonDeletionJob' + when 'Cron::NeverTouchedDossiersBrouillonDeletionJob' "every day at 5 am" when 'Cron::ExpiredPrefilledDossiersDeletionJob' "every day at 3 am" diff --git a/app/services/expired/dossiers_deletion_service.rb b/app/services/expired/dossiers_deletion_service.rb index c2b208a1d36..df4d2dc1a1b 100644 --- a/app/services/expired/dossiers_deletion_service.rb +++ b/app/services/expired/dossiers_deletion_service.rb @@ -3,8 +3,8 @@ class Expired::DossiersDeletionService < Expired::MailRateLimiter MAX_BROUILLON_DELETION_EMAILS_TO_PROCESS_PER_DAY = 10000 - def process_empty_dossiers_brouillon(deletion_window) - delete_empty_brouillons_and_notify(deletion_window) + def process_never_touched_dossiers_brouillon + delete_never_touched_brouillons end def process_expired_dossiers_brouillon @@ -56,21 +56,10 @@ def send_termine_expiration_notices ) end - def delete_empty_brouillons_and_notify(deletion_window) - empty_brouillons = Dossier.empty_brouillon(deletion_window) + def delete_never_touched_brouillons + never_touched_brouillons = Dossier.never_touched_brouillon_expired - user_notifications = group_by_user_email(empty_brouillons) - .map { |(email, dossiers)| [email, dossiers.map(&:hash_for_deletion_mail)] } - - empty_brouillons.destroy_all - - user_notifications.each do |(email, dossiers_hash)| - mail = DossierMailer.notify_brouillon_deletion( - dossiers_hash, - email - ) - send_with_delay(mail) - end + never_touched_brouillons.in_batches.destroy_all end def delete_expired_brouillons_and_notify diff --git a/spec/models/concerns/dossier_empty_concern_spec.rb b/spec/models/concerns/dossier_empty_concern_spec.rb deleted file mode 100644 index 6a6a1e524ee..00000000000 --- a/spec/models/concerns/dossier_empty_concern_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe DossierEmptyConcern do - describe 'empty_brouillon' do - let(:types) { [{ type: :text }, { type: :carte }, { type: :piece_justificative }] } - let(:procedure) { create(:procedure, types_de_champ_public: types) } - let!(:empty_brouillon) { create(:dossier, procedure:) } - let!(:empty_en_construction) { create(:dossier, :en_construction, procedure:) } - let!(:value_filled_dossier) { create(:dossier, procedure:) } - let!(:carte_filled_dossier) { create(:dossier, procedure:) } - let!(:pj_filled_dossier) { create(:dossier, procedure:) } - let(:geo_area) { build(:geo_area, :selection_utilisateur, :polygon) } - let(:attachment) { { io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png" } } - - subject { Dossier.empty_brouillon(2.days.ago..) } - - before do - value_filled_dossier.champs.first.update(value: 'filled') - carte_filled_dossier.champs.second.update(geo_areas: [geo_area]) - pj_filled_dossier.champs.third.piece_justificative_file.attach(attachment) - end - - it do - is_expected.to eq([empty_brouillon]) - end - end -end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index bafe0412746..ef29db05f81 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -2445,6 +2445,25 @@ end end + describe '#never_touched_brouillon_expired' do + let!(:dossier) { travel_to(2.weeks.ago) { create(:dossier, :brouillon, last_champ_updated_at: nil, last_champ_piece_jointe_updated_at: nil) } } + let!(:dossier_2) { travel_to(1.week.ago) { create(:dossier, :brouillon, last_champ_updated_at: nil, last_champ_piece_jointe_updated_at: nil) } } + let!(:dossier_with_champ_updated) { travel_to(2.weeks.ago) { create(:dossier, :brouillon, last_champ_updated_at: 1.day.ago, last_champ_piece_jointe_updated_at: nil) } } + let!(:dossier_with_piece_jointe_updated) { travel_to(2.weeks.ago) { create(:dossier, :brouillon, last_champ_updated_at: nil, last_champ_piece_jointe_updated_at: 1.day.ago) } } + + let!(:dossier_en_construction) { create(:dossier, :en_construction, last_champ_updated_at: nil, last_champ_piece_jointe_updated_at: nil) } + + subject { Dossier.never_touched_brouillon_expired } + + it { is_expected.to contain_exactly(dossier) } + + context 'when the dossier has been cloned' do + let!(:cloned_dossier) { dossier_with_champ_updated.clone } + + it { is_expected.to contain_exactly(dossier, cloned_dossier) } + end + end + private def count_for_month(processed_by_month, month) diff --git a/spec/services/expired/expired_dossiers_deletion_service_spec.rb b/spec/services/expired/expired_dossiers_deletion_service_spec.rb index e2d4ff56d3a..bdf61b839d8 100644 --- a/spec/services/expired/expired_dossiers_deletion_service_spec.rb +++ b/spec/services/expired/expired_dossiers_deletion_service_spec.rb @@ -90,7 +90,7 @@ end end - describe '#process_empty_dossiers_brouillon' do + describe '#process_never_touched_dossiers_brouillon' do let(:types) { [{ type: :text }] } let(:procedure_opts) { { types_de_champ_public: types } } @@ -98,7 +98,7 @@ allow(DossierMailer).to receive(:notify_brouillon_deletion).and_return(double(deliver_later: nil)) end - subject { service.process_empty_dossiers_brouillon(3.weeks.ago..2.weeks.ago) } + subject { service.process_never_touched_dossiers_brouillon(3.weeks.ago..2.weeks.ago) } context 'with empty brouillon dossiers' do let!(:empty_brouillon) { travel_to(15.days.ago) { create(:dossier, procedure: procedure) } }