Merge pull request #4974 from tchak/deletion-dossiers-termine
Implement dossiers termine deletion
This commit is contained in:
commit
93516c3101
12 changed files with 249 additions and 3 deletions
|
@ -134,7 +134,8 @@ class DossierMailer < ApplicationMailer
|
|||
def default_i18n_subject(interpolations = {})
|
||||
if interpolations[:state]
|
||||
mailer_scope = self.class.mailer_name.tr('/', '.')
|
||||
I18n.t("subject_#{interpolations[:state]}", interpolations.merge(scope: [mailer_scope, action_name]))
|
||||
state = interpolations[:state].in?(Dossier::TERMINE) ? 'termine' : interpolations[:state]
|
||||
I18n.t("subject_#{state}", interpolations.merge(scope: [mailer_scope, action_name]))
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -189,6 +189,11 @@ class Dossier < ApplicationRecord
|
|||
.joins(:procedure)
|
||||
.where("dossiers.en_instruction_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
|
||||
end
|
||||
scope :termine_close_to_expiration, -> do
|
||||
state_termine
|
||||
.joins(:procedure)
|
||||
.where("dossiers.processed_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
|
||||
end
|
||||
|
||||
scope :brouillon_expired, -> do
|
||||
state_brouillon
|
||||
|
@ -198,9 +203,14 @@ class Dossier < ApplicationRecord
|
|||
state_en_construction
|
||||
.where("en_construction_close_to_expiration_notice_sent_at + INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_EXPIRATION })
|
||||
end
|
||||
scope :termine_expired, -> do
|
||||
state_termine
|
||||
.where("termine_close_to_expiration_notice_sent_at + INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_EXPIRATION })
|
||||
end
|
||||
|
||||
scope :without_brouillon_expiration_notice_sent, -> { where(brouillon_close_to_expiration_notice_sent_at: nil) }
|
||||
scope :without_en_construction_expiration_notice_sent, -> { where(en_construction_close_to_expiration_notice_sent_at: nil) }
|
||||
scope :without_termine_expiration_notice_sent, -> { where(termine_close_to_expiration_notice_sent_at: nil) }
|
||||
|
||||
scope :discarded_brouillon_expired, -> do
|
||||
with_discarded
|
||||
|
|
|
@ -9,6 +9,11 @@ class ExpiredDossiersDeletionService
|
|||
delete_expired_en_construction_and_notify
|
||||
end
|
||||
|
||||
def self.process_expired_dossiers_termine
|
||||
send_termine_expiration_notices
|
||||
delete_expired_termine_and_notify
|
||||
end
|
||||
|
||||
def self.send_brouillon_expiration_notices
|
||||
dossiers_close_to_expiration = Dossier
|
||||
.brouillon_close_to_expiration
|
||||
|
@ -38,6 +43,16 @@ class ExpiredDossiersDeletionService
|
|||
dossiers_close_to_expiration.update_all(en_construction_close_to_expiration_notice_sent_at: Time.zone.now)
|
||||
end
|
||||
|
||||
def self.send_termine_expiration_notices
|
||||
dossiers_close_to_expiration = Dossier
|
||||
.termine_close_to_expiration
|
||||
.without_termine_expiration_notice_sent
|
||||
|
||||
send_expiration_notices(dossiers_close_to_expiration)
|
||||
|
||||
dossiers_close_to_expiration.update_all(termine_close_to_expiration_notice_sent_at: Time.zone.now)
|
||||
end
|
||||
|
||||
def self.delete_expired_brouillons_and_notify
|
||||
dossiers_to_remove = Dossier.brouillon_expired
|
||||
|
||||
|
@ -59,6 +74,10 @@ class ExpiredDossiersDeletionService
|
|||
delete_expired_and_notify(Dossier.en_construction_expired)
|
||||
end
|
||||
|
||||
def self.delete_expired_termine_and_notify
|
||||
delete_expired_and_notify(Dossier.termine_expired)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.send_expiration_notices(dossiers_close_to_expiration)
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
Bonjour,
|
||||
|
||||
%p
|
||||
= t('.header_en_construction', count: @dossiers.count)
|
||||
- if @state == Dossier.states.fetch(:en_construction)
|
||||
= t('.header_en_construction', count: @dossiers.count)
|
||||
- else
|
||||
= t('.header_termine', count: @dossiers.count)
|
||||
%ul
|
||||
- @dossiers.each do |d|
|
||||
%li
|
||||
|
@ -13,5 +16,7 @@
|
|||
%p
|
||||
- if @state == Dossier.states.fetch(:en_construction)
|
||||
= sanitize(t('.footer_en_construction', count: @dossiers.count))
|
||||
- else
|
||||
= sanitize(t('.footer_termine', count: @dossiers.count))
|
||||
|
||||
= render partial: "layouts/mailers/signature"
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
Bonjour,
|
||||
|
||||
%p
|
||||
= t('.header_en_construction', count: @dossiers.count)
|
||||
- if @state == Dossier.states.fetch(:en_construction)
|
||||
= t('.header_en_construction', count: @dossiers.count)
|
||||
- else
|
||||
= t('.header_termine', count: @dossiers.count)
|
||||
%ul
|
||||
- @dossiers.each do |d|
|
||||
%li
|
||||
|
|
|
@ -4,9 +4,18 @@ fr:
|
|||
subject_en_construction:
|
||||
one: Un dossier en construction va bientôt être supprimé
|
||||
other: Des dossiers en construction vont bientôt être supprimés
|
||||
subject_termine:
|
||||
one: Un dossier dont le traitement est terminé va bientôt être supprimé
|
||||
other: Des dossiers dont le traitement est terminé vont bientôt être supprimés
|
||||
header_en_construction:
|
||||
one: "Le dossier en construction suivant sera bientôt automatiquement supprimé :"
|
||||
other: "Les dossiers en construction suivant seront bientôt automatiquement supprimés :"
|
||||
header_termine:
|
||||
one: "Le dossier suivant dont le traitement est terminé sera bientôt automatiquement supprimé :"
|
||||
other: "Les dossiers suivant dont le traitement est terminé seront bientôt automatiquement supprimés :"
|
||||
footer_en_construction:
|
||||
one: "Vous avez <b>un mois</b> pour commencer l’instruction du dossier."
|
||||
other: "Vous avez <b>un mois</b> pour commencer l’instruction des dossiers."
|
||||
footer_termine:
|
||||
one: "Vous avez <b>un mois</b> pour archiver le dossier."
|
||||
other: "Vous avez <b>un mois</b> pour archiver les dossiers."
|
||||
|
|
|
@ -4,9 +4,15 @@ fr:
|
|||
subject_en_construction:
|
||||
one: Un dossier en construction va bientôt être supprimé
|
||||
other: Des dossiers en construction vont bientôt être supprimés
|
||||
subject_termine:
|
||||
one: Un dossier dont le traitement est terminé va bientôt être supprimé
|
||||
other: Des dossiers dont le traitement est terminé vont bientôt être supprimés
|
||||
header_en_construction:
|
||||
one: "Afin de limiter la conservation de vos données personnelles, le dossier en construction suivant sera bientôt automatiquement supprimé :"
|
||||
other: "Afin de limiter la conservation de vos données personnelles, les dossiers en construction suivant seront bientôt automatiquement supprimés :"
|
||||
header_termine:
|
||||
one: "Afin de limiter la conservation de vos données personnelles, le dossier suivant dont le traitement est terminé sera bientôt automatiquement supprimé :"
|
||||
other: "Afin de limiter la conservation de vos données personnelles, les dossiers suivant dont le traitement est terminé seront bientôt automatiquement supprimés :"
|
||||
footer:
|
||||
one: "Vous pouvez retrouver votre dossier pendant encore <b>un mois</b>. Vous n’avez rien à faire."
|
||||
other: "Vous pouvez retrouver vos dossiers pendant encore <b>un mois</b>. Vous n’avez rien à faire."
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddTermineCloseToExpirationToDossiers < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :dossiers, :termine_close_to_expiration_notice_sent_at, :datetime
|
||||
end
|
||||
end
|
|
@ -258,6 +258,7 @@ ActiveRecord::Schema.define(version: 2020_04_21_174642) do
|
|||
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
||||
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
||||
t.interval "en_construction_conservation_extension", default: "00:00:00"
|
||||
t.datetime "termine_close_to_expiration_notice_sent_at"
|
||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||
t.index ["hidden_at"], name: "index_dossiers_on_hidden_at"
|
||||
|
|
|
@ -102,6 +102,19 @@ RSpec.describe DossierMailer, type: :mailer do
|
|||
it { expect(subject.body).to include(dossier.procedure.libelle) }
|
||||
it { expect(subject.body).to include("nous nous excusons de la gène occasionnée") }
|
||||
end
|
||||
|
||||
describe 'termine' do
|
||||
let(:dossier) { create(:dossier, :accepte) }
|
||||
let(:deleted_dossier) { DeletedDossier.create_from_dossier(dossier, :expired) }
|
||||
|
||||
subject { described_class.notify_automatic_deletion_to_user([deleted_dossier], dossier.user.email) }
|
||||
|
||||
it { expect(subject.to).to eq([dossier.user.email]) }
|
||||
it { expect(subject.subject).to eq("Un dossier a été supprimé automatiquement") }
|
||||
it { expect(subject.body).to include("n° #{dossier.id} ") }
|
||||
it { expect(subject.body).to include(dossier.procedure.libelle) }
|
||||
it { expect(subject.body).not_to include("nous nous excusons de la gène occasionnée") }
|
||||
end
|
||||
end
|
||||
|
||||
describe '.notify_automatic_deletion_to_administration' do
|
||||
|
@ -126,6 +139,18 @@ RSpec.describe DossierMailer, type: :mailer do
|
|||
it { expect(subject.body).to include("PDF") }
|
||||
it { expect(subject.body).to include("Vous avez <b>un mois</b> pour commencer l’instruction du dossier.") }
|
||||
end
|
||||
|
||||
describe 'termine' do
|
||||
let(:dossier) { create(:dossier, :accepte) }
|
||||
|
||||
subject { described_class.notify_near_deletion_to_administration([dossier], dossier.user.email) }
|
||||
|
||||
it { expect(subject.subject).to eq("Un dossier dont le traitement est terminé va bientôt être supprimé") }
|
||||
it { expect(subject.body).to include("n° #{dossier.id} ") }
|
||||
it { expect(subject.body).to include(dossier.procedure.libelle) }
|
||||
it { expect(subject.body).to include("PDF") }
|
||||
it { expect(subject.body).to include("Vous avez <b>un mois</b> pour archiver le dossier.") }
|
||||
end
|
||||
end
|
||||
|
||||
describe '.notify_near_deletion_to_user' do
|
||||
|
@ -141,6 +166,19 @@ RSpec.describe DossierMailer, type: :mailer do
|
|||
it { expect(subject.body).to include("PDF") }
|
||||
it { expect(subject.body).to include("Vous pouvez retrouver votre dossier pendant encore <b>un mois</b>. Vous n’avez rien à faire.") }
|
||||
end
|
||||
|
||||
describe 'termine' do
|
||||
let(:dossier) { create(:dossier, :accepte) }
|
||||
|
||||
subject { described_class.notify_near_deletion_to_user([dossier], dossier.user.email) }
|
||||
|
||||
it { expect(subject.to).to eq([dossier.user.email]) }
|
||||
it { expect(subject.subject).to eq("Un dossier dont le traitement est terminé va bientôt être supprimé") }
|
||||
it { expect(subject.body).to include("n° #{dossier.id} ") }
|
||||
it { expect(subject.body).to include(dossier.procedure.libelle) }
|
||||
it { expect(subject.body).to include("PDF") }
|
||||
it { expect(subject.body).to include("Vous pouvez retrouver votre dossier pendant encore <b>un mois</b>. Vous n’avez rien à faire.") }
|
||||
end
|
||||
end
|
||||
|
||||
describe '.notify_groupe_instructeur_changed_to_instructeur' do
|
||||
|
|
|
@ -28,6 +28,14 @@ class DossierMailerPreview < ActionMailer::Preview
|
|||
DossierMailer.notify_near_deletion_to_administration([dossier_en_construction, dossier_en_construction], administration_email)
|
||||
end
|
||||
|
||||
def notify_termine_near_deletion_to_user
|
||||
DossierMailer.notify_near_deletion_to_user([dossier_accepte], usager_email)
|
||||
end
|
||||
|
||||
def notify_termine_near_deletion_to_administration
|
||||
DossierMailer.notify_near_deletion_to_administration([dossier_accepte, dossier_accepte], administration_email)
|
||||
end
|
||||
|
||||
def notify_brouillon_deletion
|
||||
DossierMailer.notify_brouillon_deletion([dossier.hash_for_deletion_mail], usager_email)
|
||||
end
|
||||
|
@ -83,6 +91,10 @@ class DossierMailerPreview < ActionMailer::Preview
|
|||
Dossier.new(id: 47882, state: :en_construction, procedure: procedure, user: User.new(email: "usager@example.com"))
|
||||
end
|
||||
|
||||
def dossier_accepte
|
||||
Dossier.new(id: 47882, state: :accepte, procedure: procedure, user: User.new(email: "usager@example.com"))
|
||||
end
|
||||
|
||||
def procedure
|
||||
Procedure.new(id: 1234, libelle: 'Dotation d’Équipement des Territoires Ruraux - Exercice 2019', service: service, logo: Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png'), auto_archive_on: Time.zone.today + Dossier::REMAINING_DAYS_BEFORE_CLOSING.days)
|
||||
end
|
||||
|
|
|
@ -268,4 +268,141 @@ describe ExpiredDossiersDeletionService do
|
|||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_2], dossier_2.procedure.administrateurs.first.email) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#send_termine_expiration_notices' do
|
||||
before { Timecop.freeze(Time.zone.now) }
|
||||
after { Timecop.return }
|
||||
|
||||
before do
|
||||
allow(DossierMailer).to receive(:notify_near_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
allow(DossierMailer).to receive(:notify_near_deletion_to_administration).and_return(double(deliver_later: nil))
|
||||
end
|
||||
|
||||
context 'with a single dossier' do
|
||||
let!(:dossier) { create(:dossier, :accepte, :followed, procedure: procedure, processed_at: processed_at) }
|
||||
|
||||
before { ExpiredDossiersDeletionService.send_termine_expiration_notices }
|
||||
|
||||
context 'when the dossier is not near deletion' do
|
||||
let(:processed_at) { (conservation_par_defaut - 1.month - 1.day).ago }
|
||||
|
||||
it { expect(dossier.reload.termine_close_to_expiration_notice_sent_at).to be_nil }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_near_deletion_to_user) }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_near_deletion_to_administration) }
|
||||
end
|
||||
|
||||
context 'when the dossier is near deletion' do
|
||||
let(:processed_at) { (conservation_par_defaut - 1.month + 1.day).ago }
|
||||
|
||||
it { expect(dossier.reload.termine_close_to_expiration_notice_sent_at).not_to be_nil }
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).twice }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).with([dossier], dossier.user.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with([dossier], dossier.procedure.administrateurs.first.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with([dossier], dossier.followers_instructeurs.first.email) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with 2 dossiers to notice' do
|
||||
let!(:dossier_1) { create(:dossier, :accepte, procedure: procedure, user: user, processed_at: (conservation_par_defaut - 1.month + 1.day).ago) }
|
||||
let!(:dossier_2) { create(:dossier, :accepte, procedure: procedure_2, user: user, processed_at: (conservation_par_defaut - 1.month + 1.day).ago) }
|
||||
|
||||
let!(:instructeur) { create(:instructeur) }
|
||||
|
||||
before do
|
||||
instructeur.followed_dossiers << dossier_1 << dossier_2
|
||||
ExpiredDossiersDeletionService.send_termine_expiration_notices
|
||||
end
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).exactly(3).times }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).with(match_array([dossier_1, dossier_2]), user.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with(match_array([dossier_1, dossier_2]), instructeur.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with([dossier_1], dossier_1.procedure.administrateurs.first.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with([dossier_2], dossier_2.procedure.administrateurs.first.email) }
|
||||
end
|
||||
|
||||
context 'when an instructeur is also administrateur' do
|
||||
let!(:administrateur) { procedure.administrateurs.first }
|
||||
let!(:dossier) { create(:dossier, :accepte, procedure: procedure, processed_at: (conservation_par_defaut - 1.month + 1.day).ago) }
|
||||
|
||||
before do
|
||||
administrateur.instructeur.followed_dossiers << dossier
|
||||
ExpiredDossiersDeletionService.send_termine_expiration_notices
|
||||
end
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).with([dossier], dossier.user.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_near_deletion_to_administration).with([dossier], administrateur.email) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete_expired_termine_and_notify' do
|
||||
before { Timecop.freeze(Time.zone.now) }
|
||||
after { Timecop.return }
|
||||
|
||||
before do
|
||||
allow(DossierMailer).to receive(:notify_automatic_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
allow(DossierMailer).to receive(:notify_automatic_deletion_to_administration).and_return(double(deliver_later: nil))
|
||||
end
|
||||
|
||||
context 'with a single dossier' do
|
||||
let!(:dossier) { create(:dossier, :accepte, :followed, procedure: procedure, termine_close_to_expiration_notice_sent_at: notice_sent_at) }
|
||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
|
||||
|
||||
before { ExpiredDossiersDeletionService.delete_expired_termine_and_notify }
|
||||
|
||||
context 'when no notice has been sent' do
|
||||
let(:notice_sent_at) { nil }
|
||||
|
||||
it { expect { dossier.reload }.not_to raise_error }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_user) }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_administration) }
|
||||
end
|
||||
|
||||
context 'when a notice has been sent not so long ago' do
|
||||
let(:notice_sent_at) { (warning_period - 4.days).ago }
|
||||
|
||||
it { expect { dossier.reload }.not_to raise_error }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_user) }
|
||||
it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_administration) }
|
||||
end
|
||||
|
||||
context 'when a notice has been sent a long time ago' do
|
||||
let(:notice_sent_at) { (warning_period + 4.days).ago }
|
||||
|
||||
it { expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound) }
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).with([deleted_dossier], dossier.user.email) }
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).twice }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier], dossier.procedure.administrateurs.first.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier], dossier.followers_instructeurs.first.email) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with 2 dossiers to delete' do
|
||||
let!(:dossier_1) { create(:dossier, :accepte, procedure: procedure, user: user, termine_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) }
|
||||
let!(:dossier_2) { create(:dossier, :refuse, procedure: procedure_2, user: user, termine_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) }
|
||||
let(:deleted_dossier_1) { DeletedDossier.find_by(dossier_id: dossier_1.id) }
|
||||
let(:deleted_dossier_2) { DeletedDossier.find_by(dossier_id: dossier_2.id) }
|
||||
|
||||
let!(:instructeur) { create(:instructeur) }
|
||||
|
||||
before do
|
||||
instructeur.followed_dossiers << dossier_1 << dossier_2
|
||||
ExpiredDossiersDeletionService.delete_expired_termine_and_notify
|
||||
end
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).with(match_array([deleted_dossier_1, deleted_dossier_2]), user.email) }
|
||||
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).thrice }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with(match_array([deleted_dossier_1, deleted_dossier_2]), instructeur.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_1], dossier_1.procedure.administrateurs.first.email) }
|
||||
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_2], dossier_2.procedure.administrateurs.first.email) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue