Merge pull request #10488 from demarches-simplifiees/improve-mails-for-deleted-dossiers-ldu

[usager] Laisser un délai avant suppression des dossiers expirés
This commit is contained in:
Lisa Durand 2024-07-25 15:14:30 +00:00 committed by GitHub
commit e93ea356ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 436 additions and 239 deletions

View file

@ -23,6 +23,12 @@ module Instructeurs
redirect_back(fallback_location: instructeur_dossier_path(@dossier.procedure, @dossier))
end
def extend_conservation_and_restore
dossier.extend_conservation_and_restore(1.month, current_instructeur)
flash[:notice] = t('views.instructeurs.dossiers.archived_dossier')
redirect_back(fallback_location: instructeur_dossier_path(@dossier.procedure, @dossier))
end
def geo_data
send_data dossier.to_feature_collection.to_json,
type: 'application/json',
@ -376,6 +382,10 @@ module Instructeurs
Dossier
.where(id: current_instructeur.dossiers.visible_by_administration)
.or(Dossier.where(id: current_user.dossiers.for_procedure_preview))
elsif action_name == 'extend_conservation_and_restore'
Dossier
.where(id: current_instructeur.dossiers.visible_by_administration)
.or(Dossier.where(id: current_instructeur.dossiers.hidden_by_expired))
else
current_instructeur.dossiers.visible_by_administration
end

View file

@ -57,7 +57,7 @@ module Users
@user_dossiers = current_user.dossiers.state_not_termine.merge(@dossiers_visibles)
@dossiers_traites = current_user.dossiers.state_termine.merge(@dossiers_visibles)
@dossiers_invites = current_user.dossiers_invites.merge(@dossiers_visibles)
@dossiers_supprimes_recemment = current_user.dossiers.hidden_by_user.merge(ordered_dossiers)
@dossiers_supprimes_recemment = (current_user.dossiers.hidden_by_user.or(current_user.dossiers.hidden_by_expired)).merge(ordered_dossiers)
@dossier_transferes = @dossiers_visibles.where(dossier_transfer_id: DossierTransfer.for_email(current_user.email))
@dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.merge(@dossiers_visibles)
@dossiers_supprimes_definitivement = deleted_dossiers
@ -259,6 +259,12 @@ module Users
redirect_back(fallback_location: dossier_path(@dossier))
end
def extend_conservation_and_restore
dossier.extend_conservation_and_restore(dossier.procedure.duree_conservation_dossiers_dans_ds.months, current_user)
flash[:notice] = t('views.users.dossiers.archived_dossier', duree_conservation_dossiers_dans_ds: dossier.procedure.duree_conservation_dossiers_dans_ds)
redirect_back(fallback_location: dossier_path(@dossier))
end
def modifier
@dossier = dossier_with_champs
end
@ -530,6 +536,8 @@ module Users
Dossier.visible_by_user.or(Dossier.for_procedure_preview).or(Dossier.for_editing_fork)
elsif action_name == 'restore'
Dossier.hidden_by_user
elsif action_name == 'extend_conservation_and_restore'
Dossier.visible_by_user.or(Dossier.hidden_by_expired)
else
Dossier.visible_by_user
end

View file

@ -129,32 +129,32 @@ class DossierMailer < ApplicationMailer
mail(to: to_email, subject: @subject)
end
def notify_deletion_to_administration(deleted_dossier, to_email)
def notify_deletion_to_administration(hidden_dossier, to_email)
configure_defaults_for_email(to_email)
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
@deleted_dossier = deleted_dossier
@subject = default_i18n_subject(dossier_id: hidden_dossier.id)
@hidden_dossier = hidden_dossier
mail(to: to_email, subject: @subject)
end
def notify_automatic_deletion_to_user(deleted_dossiers, to_email)
def notify_automatic_deletion_to_user(hidden_dossiers, to_email)
configure_defaults_for_email(to_email)
I18n.with_locale(deleted_dossiers.first.user_locale) do
@state = deleted_dossiers.first.state
@subject = default_i18n_subject(count: deleted_dossiers.size)
@deleted_dossiers = deleted_dossiers
I18n.with_locale(hidden_dossiers.first.user_locale) do
@state = hidden_dossiers.first.state
@subject = default_i18n_subject(count: hidden_dossiers.size)
@hidden_dossiers = hidden_dossiers
mail(to: to_email, subject: @subject)
end
end
def notify_automatic_deletion_to_administration(deleted_dossiers, to_email)
def notify_automatic_deletion_to_administration(hidden_dossiers, to_email)
configure_defaults_for_email(to_email)
@subject = default_i18n_subject(count: deleted_dossiers.size)
@deleted_dossiers = deleted_dossiers
@subject = default_i18n_subject(count: hidden_dossiers.size)
@hidden_dossiers = hidden_dossiers
mail(to: to_email, subject: @subject)
end

View file

@ -221,10 +221,12 @@ class Dossier < ApplicationRecord
scope :prefilled, -> { where(prefilled: true) }
scope :hidden_by_user, -> { where.not(hidden_by_user_at: nil) }
scope :hidden_by_administration, -> { where.not(hidden_by_administration_at: nil) }
scope :visible_by_user, -> { where(for_procedure_preview: false).where(hidden_by_user_at: nil, editing_fork_origin_id: nil) }
scope :hidden_by_expired, -> { where.not(hidden_by_expired_at: nil) }
scope :visible_by_user, -> { where(for_procedure_preview: false, hidden_by_user_at: nil, editing_fork_origin_id: nil, hidden_by_expired_at: nil) }
scope :visible_by_administration, -> {
state_not_brouillon
.where(hidden_by_administration_at: nil)
.where(hidden_by_expired_at: nil)
.merge(visible_by_user.or(state_not_en_construction))
}
scope :visible_by_user_or_administration, -> { visible_by_user.or(visible_by_administration) }
@ -363,12 +365,12 @@ class Dossier < ApplicationRecord
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 :deleted_by_user_expired, -> { where('dossiers.hidden_by_user_at < ?', 1.week.ago) }
scope :deleted_by_administration_expired, -> { where('dossiers.hidden_by_administration_at < ?', 1.week.ago) }
scope :en_brouillon_expired_to_delete, -> { state_brouillon.deleted_by_user_expired }
scope :en_construction_expired_to_delete, -> { state_en_construction.deleted_by_user_expired }
scope :termine_expired_to_delete, -> { state_termine.deleted_by_user_expired.deleted_by_administration_expired }
scope :deleted_by_automatic_expired, -> { where('dossiers.hidden_by_expired_at < ?', 1.week.ago) }
scope :en_brouillon_expired_to_delete, -> { state_brouillon.deleted_by_user_expired.or(state_brouillon.deleted_by_automatic_expired) }
scope :en_construction_expired_to_delete, -> { state_en_construction.deleted_by_user_expired.or(state_en_construction.deleted_by_automatic_expired) }
scope :termine_expired_to_delete, -> { state_termine.deleted_by_user_expired.deleted_by_administration_expired.or(state_termine.deleted_by_automatic_expired) }
scope :brouillon_near_procedure_closing_date, -> do
# select users who have submitted dossier for the given 'procedures.id'
@ -415,7 +417,7 @@ class Dossier < ApplicationRecord
when 'tous'
visible_by_administration.all_state
when 'supprimes_recemment'
hidden_by_administration.state_termine
hidden_by_administration.state_termine.or(hidden_by_expired)
when 'archives'
visible_by_administration.archived
when 'expirant'
@ -600,6 +602,10 @@ class Dossier < ApplicationRecord
termine? || reason == :procedure_removed
end
def can_be_deleted_by_automatic?(reason)
reason == :expired && !en_instruction?
end
def can_terminer_automatiquement_by_sva_svr?
sva_svr_decision_triggered_at.nil? && !pending_correction? && (sva_svr_decision_on.today? || sva_svr_decision_on.past?)
end
@ -645,7 +651,12 @@ class Dossier < ApplicationRecord
def close_to_expiration?
return false if en_instruction?
expiration_notification_date < Time.zone.now
expiration_notification_date < Time.zone.now && Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks.ago < expiration_notification_date
end
def has_expired?
return false if en_instruction?
expiration_notification_date < Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks.ago
end
def after_notification_expiration_date
@ -677,6 +688,12 @@ class Dossier < ApplicationRecord
termine_close_to_expiration_notice_sent_at: nil)
end
def extend_conservation_and_restore(conservation_extension, author)
extend_conservation(conservation_extension)
update(hidden_by_expired_at: nil, hidden_by_reason: nil)
restore(author)
end
def show_procedure_state_warning?
procedure.discarded? || (brouillon? && !procedure.dossier_can_transition_to_en_construction?)
end
@ -766,6 +783,10 @@ class Dossier < ApplicationRecord
!procedure.brouillon? && !brouillon?
end
def hidden_by_expired?
hidden_by_expired_at.present?
end
def hidden_by_user?
hidden_by_user_at.present?
end
@ -820,37 +841,32 @@ class Dossier < ApplicationRecord
end
end
def expired_keep_track_and_destroy!
transaction do
DeletedDossier.create_from_dossier(self, :expired)
log_automatic_dossier_operation(:supprimer, self)
dossier_operation_logs.purge_discarded
destroy!
end
true
rescue
false
end
def author_is_user(author)
def is_user?(author)
author.is_a?(User)
end
def author_is_administration(author)
def is_administration?(author)
author.is_a?(Instructeur) || author.is_a?(Administrateur) || author.is_a?(SuperAdmin)
end
def is_automatic?(author)
author == :automatic
end
def hide_and_keep_track!(author, reason)
transaction do
if author_is_administration(author) && can_be_deleted_by_administration?(reason)
if is_administration?(author) && can_be_deleted_by_administration?(reason)
update(hidden_by_administration_at: Time.zone.now, hidden_by_reason: reason)
elsif author_is_user(author) && can_be_deleted_by_user?
log_dossier_operation(author, :supprimer, self)
elsif is_user?(author) && can_be_deleted_by_user?
update(hidden_by_user_at: Time.zone.now, dossier_transfer_id: nil, hidden_by_reason: reason)
log_dossier_operation(author, :supprimer, self)
elsif is_automatic?(author) && can_be_deleted_by_automatic?(reason)
update(hidden_by_expired_at: Time.zone.now, hidden_by_reason: reason)
log_automatic_dossier_operation(:supprimer, self)
else
raise "Unauthorized dossier hide attempt Dossier##{id} by #{author} for reason #{reason}"
end
log_dossier_operation(author, :supprimer, self)
end
if en_construction? && !hidden_by_administration?
@ -863,14 +879,18 @@ class Dossier < ApplicationRecord
def restore(author)
transaction do
if author_is_administration(author)
if is_administration?(author)
update(hidden_by_administration_at: nil)
elsif author_is_user(author)
elsif is_user?(author)
update(hidden_by_user_at: nil)
end
if !hidden_by_user? && !hidden_by_administration?
update(hidden_by_reason: nil)
elsif hidden_by_user?
update(hidden_by_reason: :user_request)
elsif hidden_by_administration?
update(hidden_by_reason: :instructeur_request)
end
log_dossier_operation(author, :restaurer, self)

View file

@ -227,18 +227,18 @@ class Instructeur < ApplicationRecord
def dossiers_count_summary(groupe_instructeur_ids)
query = <<~EOF
SELECT
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.id IS NULL) AS a_suivre,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.instructeur_id = :instructeur_id) AS suivis,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS traites,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND not archived) AS tous,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND archived) AS archives,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NOT NULL AND not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS supprimes_recemment,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND procedures.procedure_expires_when_termine_enabled
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.id IS NULL) AS a_suivre,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.instructeur_id = :instructeur_id) AS suivis,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS traites,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND not archived) AS tous,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND archived) AS archives,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NOT NULL AND not archived OR dossiers.hidden_by_expired_at IS NOT NULL) AS supprimes_recemment,
COUNT(DISTINCT dossiers.id) FILTER (where dossiers.hidden_by_administration_at IS NULL AND dossiers.hidden_by_expired_at IS NULL AND procedures.procedure_expires_when_termine_enabled
AND (
dossiers.state in ('accepte', 'refuse', 'sans_suite')
AND dossiers.processed_at + dossiers.conservation_extension + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now
) OR (
dossiers.state in ('en_construction')
dossiers.state in ('en_construction') AND dossiers.hidden_by_expired_at IS NULL
AND dossiers.en_construction_at + dossiers.conservation_extension + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now
)
) AS expirant

View file

@ -1,5 +1,5 @@
class DossierProjectionService
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :hidden_by_administration_at, :for_tiers, :prenom, :nom, :batch_operation_id, :sva_svr_decision_on, :corrections, :columns) do
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :hidden_by_administration_at, :hidden_by_reason, :for_tiers, :prenom, :nom, :batch_operation_id, :sva_svr_decision_on, :corrections, :columns) do
def pending_correction?
return false if corrections.blank?
@ -44,13 +44,14 @@ class DossierProjectionService
batch_operation_field = { TABLE => 'self', COLUMN => 'batch_operation_id' }
hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' }
hidden_by_administration_at_field = { TABLE => 'self', COLUMN => 'hidden_by_administration_at' }
hidden_by_reason_field = { TABLE => 'self', COLUMN => 'hidden_by_reason' }
for_tiers_field = { TABLE => 'self', COLUMN => 'for_tiers' }
individual_first_name = { TABLE => 'individual', COLUMN => 'prenom' }
individual_last_name = { TABLE => 'individual', COLUMN => 'nom' }
sva_svr_decision_on_field = { TABLE => 'self', COLUMN => 'sva_svr_decision_on' }
dossier_corrections = { TABLE => 'dossier_corrections', COLUMN => 'resolved_at' }
champ_value = champ_value_formatter(dossiers_ids, fields)
([state_field, archived_field, sva_svr_decision_on_field, hidden_by_user_at_field, hidden_by_administration_at_field, for_tiers_field, individual_first_name, individual_last_name, batch_operation_field, dossier_corrections] + fields) # the view needs state and archived dossier attributes
([state_field, archived_field, sva_svr_decision_on_field, hidden_by_user_at_field, hidden_by_administration_at_field, hidden_by_reason_field, for_tiers_field, individual_first_name, individual_last_name, batch_operation_field, dossier_corrections] + fields)
.each { |f| f[:id_value_h] = {} }
.group_by { |f| f[TABLE] } # one query per table
.each do |table, fields|
@ -73,7 +74,7 @@ class DossierProjectionService
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
.each do |id, *columns|
fields.zip(columns).each do |field, value|
if [state_field, archived_field, hidden_by_user_at_field, hidden_by_administration_at_field, for_tiers_field, batch_operation_field, sva_svr_decision_on_field].include?(field)
if [state_field, archived_field, hidden_by_user_at_field, hidden_by_administration_at_field, hidden_by_reason_field, for_tiers_field, batch_operation_field, sva_svr_decision_on_field].include?(field)
field[:id_value_h][id] = value
else
field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime
@ -150,6 +151,7 @@ class DossierProjectionService
archived_field[:id_value_h][dossier_id],
hidden_by_user_at_field[:id_value_h][dossier_id],
hidden_by_administration_at_field[:id_value_h][dossier_id],
hidden_by_reason_field[:id_value_h][dossier_id],
for_tiers_field[:id_value_h][dossier_id],
individual_first_name[:id_value_h][dossier_id],
individual_last_name[:id_value_h][dossier_id],

View file

@ -93,27 +93,26 @@ class Expired::DossiersDeletionService < Expired::MailRateLimiter
administration_notifications = group_by_fonctionnaire_email(dossiers_to_remove)
.map { |(email, dossiers)| [email, dossiers.map(&:id)] }
deleted_dossier_ids = []
hidden_dossier_ids = []
dossiers_to_remove.find_each do |dossier|
if dossier.expired_keep_track_and_destroy!
deleted_dossier_ids << dossier.id
end
dossier.hide_and_keep_track!(:automatic, :expired)
hidden_dossier_ids << dossier.id
end
user_notifications.each do |(email, dossier_ids)|
dossier_ids = dossier_ids.intersection(deleted_dossier_ids)
dossier_ids = dossier_ids.intersection(hidden_dossier_ids)
if dossier_ids.present?
mail = DossierMailer.notify_automatic_deletion_to_user(
DeletedDossier.where(dossier_id: dossier_ids).to_a,
Dossier.where(id: dossier_ids).to_a,
email
)
send_with_delay(mail)
end
end
administration_notifications.each do |(email, dossier_ids)|
dossier_ids = dossier_ids.intersection(deleted_dossier_ids)
dossier_ids = dossier_ids.intersection(hidden_dossier_ids)
if dossier_ids.present?
mail = DossierMailer.notify_automatic_deletion_to_administration(
DeletedDossier.where(dossier_id: dossier_ids).to_a,
Dossier.where(id: dossier_ids).to_a,
email
)
send_with_delay(mail)

View file

@ -3,9 +3,14 @@
%p= t(:hello, scope: [:views, :shared, :greetings])
%p
= t('.header', count: @deleted_dossiers.size)
= t('.header', count: @hidden_dossiers.size)
%ul
- @deleted_dossiers.each do |d|
%li n° #{d.dossier_id} (#{d.procedure.libelle})
- @hidden_dossiers.each do |d|
%li n° #{d.id} (#{d.procedure.libelle})
%p
= t('.footer', count: @hidden_dossiers.size)
= link_to("mes dossiers", dossiers_url)
\.
= render partial: "layouts/mailers/signature"

View file

@ -3,15 +3,14 @@
%p= t(:hello, scope: [:views, :shared, :greetings])
%p
= t('.header', count: @deleted_dossiers.size)
= t('.header', count: @hidden_dossiers.size)
%ul
- @deleted_dossiers.each do |d|
%li N° #{d.dossier_id} (#{d.procedure.libelle})
- @hidden_dossiers.each do |d|
%li N° #{d.id} (#{d.procedure.libelle})
%p
%strong= t('.account_active', count: @deleted_dossiers.size)
- if @state == Dossier.states.fetch(:en_construction)
%p= t('.footer_en_construction', count: @deleted_dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks))
= t('.footer', count: @hidden_dossiers.size)
= link_to("mes dossiers", dossiers_url)
\.
= render partial: "layouts/mailers/signature"

View file

@ -8,6 +8,8 @@
- @dossiers.each do |d|
%li= link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d))
%p= sanitize(t('.footer', count: @dossiers.size))
%p
= t('.account_active', count: @dossiers.size)
= render partial: "layouts/mailers/signature"

View file

@ -3,6 +3,6 @@
%p= t(:hello, scope: [:views, :shared, :greetings])
%p
= t('.body', dossier_id: @deleted_dossier.dossier_id, procedure: @deleted_dossier.procedure.libelle)
= t('.body', dossier_id: @hidden_dossier.id, procedure: @hidden_dossier.procedure.libelle)
= render partial: "layouts/mailers/signature"

View file

@ -4,18 +4,17 @@
%p
- if @state == Dossier.states.fetch(:en_construction)
= t('.header_en_construction', count: @dossiers.size)
= t('.header_en_construction', count: @dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks))
- else
= t('.header_termine', count: @dossiers.size)
= t('.header_termine', count: @dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks))
%ul
- @dossiers.each do |d|
%li
#{link_to("N° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}. Retrouvez le dossier au format #{link_to("PDF", instructeur_dossier_url(d.procedure, d, format: :pdf))}
%p
- if @state == Dossier.states.fetch(:en_construction)
= sanitize(t('.footer_en_construction', count: @dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks)))
- else
= sanitize(t('.footer_termine', count: @dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks)))
- if @state == Dossier.states.fetch(:en_construction)
%p
= sanitize(t('.footer_en_construction'))
= render partial: "layouts/mailers/signature"

View file

@ -12,13 +12,15 @@
%li
#{link_to("N° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}
%p
%strong= t('.account_active', count: @dossiers.size)
%p
- if @state == Dossier.states.fetch(:en_construction)
= sanitize(t('.footer_en_construction', count: @dossiers.size, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks)))
- else
= sanitize(t('.footer_termine', count: @dossiers.size, dossiers_url: dossiers_url, remaining_weeks_before_expiration: distance_of_time_in_words(Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks)))
= link_to("mes dossiers", dossiers_url)
\.
%p
= t('.account_active', count: @dossiers.size)
= render partial: "layouts/mailers/signature"

View file

@ -6,8 +6,9 @@
- if dossier.conservation_extension.positive?
= t('instructeurs.dossiers.header.banner.expiration_date_extended')
- if dossier.close_to_expiration?
= render Dsfr::CalloutComponent.new(title: t('instructeurs.dossiers.header.banner.title'), theme: :warning) do |c|
- if dossier.close_to_expiration? || dossier.has_expired?
- title = dossier.has_expired? ? 'title_expired' : 'title'
= render Dsfr::CalloutComponent.new(title: t("instructeurs.dossiers.header.banner.#{title}"), theme: :warning) do |c|
- c.with_body do
- if dossier.brouillon?
= t('instructeurs.dossiers.header.banner.states.brouillon')

View file

@ -8,6 +8,7 @@
dossier_is_followed: current_instructeur&.follow?(dossier),
close_to_expiration: dossier.close_to_expiration?,
hidden_by_administration: dossier.hidden_by_administration?,
hidden_by_expired: dossier.hidden_by_expired?,
has_pending_correction: dossier.pending_correction?,
has_blocking_pending_correction: dossier.procedure.feature_enabled?(:blocking_pending_correction) && dossier.pending_correction?,
turbo: true,

View file

@ -1,7 +1,13 @@
- if hidden_by_administration
- if hidden_by_administration && hidden_by_expired
%li
= button_to repousser_expiration_and_restore_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, class: "fr-btn fr-icon-refresh-line" do
= t('views.instructeurs.dossiers.restore_and_extend')
- elsif hidden_by_administration
%li
= button_to restore_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, class: "fr-btn fr-icon-refresh-line" do
= t('views.instructeurs.dossiers.restore')
- elsif close_to_expiration || Dossier::TERMINE.include?(state)
%li
- if close_to_expiration

View file

@ -144,11 +144,12 @@
- if p.hidden_by_administration_at.present?
%span.cell-link
= column
= "- #{t('views.instructeurs.dossiers.deleted_by_user')}" if p.hidden_by_user_at.present?
- if p.hidden_by_user_at.present?
= "- #{t("views.instructeurs.dossiers.deleted_reason.#{p.hidden_by_reason}")}"
- else
%a.cell-link{ href: path }
= column
= "- #{t('views.instructeurs.dossiers.deleted_by_user')}" if p.hidden_by_user_at.present?
= "- #{t('views.instructeurs.dossiers.deleted_reason', reason: p.hidden_by_reason)}" if p.hidden_by_user_at.present?
%td.status-col
- status = [status_badge(p.state)]
@ -172,6 +173,7 @@
dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id),
close_to_expiration: @statut == 'expirant',
hidden_by_administration: @statut == 'supprimes_recemment',
hidden_by_expired: p.hidden_by_reason == 'expired',
sva_svr: @procedure.sva_svr_enabled?,
has_blocking_pending_correction: @procedure.feature_enabled?(:blocking_pending_correction) && p.pending_correction?,
turbo: false,

View file

@ -102,6 +102,7 @@
dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id),
close_to_expiration: nil,
hidden_by_administration: nil,
hidden_by_expired: nil,
sva_svr: p.sva_svr_decision_on.present?,
has_blocking_pending_correction: p.pending_correction? && Flipper.enabled?(:blocking_pending_correction, ProcedureFlipperActor.new(procedure_id)),
turbo: false,

View file

@ -19,8 +19,7 @@
= t('views.users.dossiers.dossiers_list.n_dossier')
= dossier.dossier_id
%span.fr-badge.fr-badge--sm.fr-badge--warning
= t('views.users.dossiers.dossiers_list.deleted_badge')
= status_badge(dossier.state, 'fr-mb-1w')
= paginate deleted_dossiers, views_prefix: 'shared'

View file

@ -16,9 +16,12 @@
%p.fr-icon--sm.fr-icon-user-line
= demandeur_dossier(dossier)
- if dossier.hidden_by_user?
- if dossier.hidden_by_expired?
%p.fr-icon--sm.fr-icon-delete-line
= t('views.users.dossiers.dossiers_list.deleted', date: l(dossier.hidden_by_user_at.to_date))
= t('views.users.dossiers.dossiers_list.deleted_by_automatic', date: l(dossier.hidden_by_expired_at.to_date))
- elsif dossier.hidden_by_user?
%p.fr-icon--sm.fr-icon-delete-line
= t('views.users.dossiers.dossiers_list.deleted_by_user', date: l(dossier.hidden_by_user_at.to_date))
- else
%p.fr-icon--sm.fr-icon-edit-box-line
- if dossier.depose_at.present?
@ -40,11 +43,7 @@
= t('views.users.dossiers.dossiers_list.n_dossier')
= number_with_html_delimiter(dossier.id)
- if @statut == "dossiers-supprimes-recemment"
%span.fr-badge.fr-badge--sm.fr-badge--warning
= t('views.users.dossiers.dossiers_list.deleted_badge')
- else
= status_badge_user(dossier, 'fr-mb-1w')
= status_badge_user(dossier, 'fr-mb-1w')
- if dossier.pending_correction?
%br
@ -103,8 +102,18 @@
- if @statut == "dossiers-supprimes-recemment"
.flex.justify-end
= link_to restore_dossier_path(dossier.id), method: :patch, class: "fr-btn fr-btn--sm" do
Restaurer
- if dossier.hidden_by_reason != 'expired'
= link_to restore_dossier_path(dossier.id), method: :patch, class: "fr-btn fr-btn--sm" do
Restaurer
- else
- if dossier.expiration_can_be_extended?
= button_to users_dossier_repousser_expiration_and_restore_path(dossier), class: 'fr-btn fr-btn--sm' do
Restaurer et étendre la conservation
- else
= render(partial: 'users/dossiers/show/download_dossier', locals: { dossier: dossier })
= paginate dossiers, views_prefix: 'shared'

View file

@ -3,8 +3,9 @@
%p.expires_at
%small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months)
- if dossier.close_to_expiration?
= render Dsfr::CalloutComponent.new(title: t('users.dossiers.header.banner.title'), theme: :warning) do |c|
- if dossier.close_to_expiration? || dossier.has_expired?
- title = dossier.has_expired? ? 'title_expired' : 'title'
= render Dsfr::CalloutComponent.new(title: t("users.dossiers.header.banner.#{title}"), theme: :warning) do |c|
- c.with_body do
- if dossier.brouillon?
= t('users.dossiers.header.banner.states.brouillon')

View file

@ -406,7 +406,6 @@ en:
expirant: Records will not expire prior to the data retention period.
archived_dossier: "This file will be kept for an additional month"
delete_dossier: "Delete file"
deleted_by_user: "File deleted by user"
acts_on_behalf: "acts for"
deleted_by_administration: "File deleted by administration"
restore: "Restore"
@ -523,7 +522,6 @@ en:
updated_at: updated at %{date}
shared_with: File shared by %{owner} with
deleted: Deleted at %{date}
deleted_badge: Deleted
procedure_closed:
brouillon:
internal_procedure_html: This procedure is closed, you cannot submit this file. We invite you to submit a new one on the %{link} which replaces it

View file

@ -405,10 +405,13 @@ fr:
expirant: Les dossiers nexpireront pas avant la période de conservation des données.
archived_dossier: "Le dossier sera conservé 1 mois supplémentaire"
delete_dossier: "Supprimer le dossier"
deleted_by_user: "Dossier supprimé par lusager"
deleted_reason:
user_request: supprimé par l'usager
expired: a expiré
acts_on_behalf: "agit pour"
deleted_by_administration: "Dossier supprimé par ladministration"
restore: "Restaurer"
restore_and_extend: "Restaurer et étendre la conservation"
filters:
title: Sélectionner un filtre
select_all: Tout selectionner
@ -536,7 +539,8 @@ fr:
updated_at: modifié le %{date}
shared_with: Dossier partagé par %{owner} avec
deleted: Supprimé le %{date}
deleted_badge: Supprimé
deleted_by_user: Supprimé le %{date} par l'usager
deleted_by_automatic: Supprimé le %{date} automatiquement du à la date d'expiration
dossier_action:
edit_dossier: "Modifier le dossier"
start_other_dossier: "Commencer un nouveau dossier"

View file

@ -2,8 +2,11 @@ fr:
dossier_mailer:
notify_automatic_deletion_to_administration:
subject:
one: "Un dossier a été supprimé automatiquement"
other: "Des dossiers ont été supprimés automatiquement"
one: "Un dossier a été supprimé"
other: "Des dossiers ont été supprimés"
header:
one: "Le délai maximal de conservation du dossier suivant a été atteint, celui-ci a donc été supprimé :"
other: "Le délai maximal de conservation des dossiers suivants a été atteint, ceux-ci ont donc été supprimés :"
one: "Le délai maximal de conservation du dossier a été atteint, celui-ci a donc été supprimé :"
other: "Le délai maximal de conservation des dossiers a été atteint, ceux-ci ont donc été supprimés :"
footer:
one: Vous pouvez retrouver ce dossier pendant encore une semaine depuis longlet « Supprimé » sur la page
other: Vous pouvez retrouver ces dossiers pendant encore une semaine depuis longlet « Supprimés » sur la page

View file

@ -2,14 +2,11 @@ fr:
dossier_mailer:
notify_automatic_deletion_to_user:
subject:
one: "Un dossier a été supprimé automatiquement de votre compte"
other: "Des dossiers ont été supprimés automatiquement de votre compte"
one: "Un dossier a été supprimé de votre compte"
other: "Des dossiers ont été supprimés de votre compte"
header:
one: "Le délai maximum pour la conservation du dossier suivant a été atteint.\nLe dossier suivant a été automatiquement supprimé :"
other: "Le délai maximum pour la conservation des dossiers suivants a été atteint.\nLes dossiers suivants ont été automatiquement supprimés :"
account_active:
one: Votre compte reste activé sur Démarches Simplifiées, seul le dossier est supprimé.
other: Votre compte reste activé sur Démarches Simplifiées, seuls les dossiers ont été supprimés.
footer_en_construction:
one: "Le dossier ne sera pas traité, nous nous excusons de la gêne occasionnée."
other: "Les dossiers ne seront pas traités, nous nous excusons de la gêne occasionnée."
one: "Le délai maximum pour la conservation du dossier a été atteint.\nLe dossier suivant a été supprimé :"
other: "Le délai maximum pour la conservation des dossiers a été atteint.\nLes dossiers suivants ont été supprimés :"
footer:
one: Vous pouvez retrouver ce dossier pendant encore une semaine depuis longlet « Supprimé » sur la page
other: Vous pouvez retrouver ces dossiers pendant encore une semaine depuis longlet « Supprimés » sur la page

View file

@ -2,8 +2,8 @@ fr:
dossier_mailer:
notify_brouillon_deletion:
subject:
one: "Un dossier en brouillon a été supprimé automatiquement"
other: "Des dossiers en brouillon ont été supprimés automatiquement"
one: "Un dossier en brouillon a été supprimé"
other: "Des dossiers en brouillon ont été supprimés"
header:
one: "Le délai maximum de conservation du dossier en brouillon suivant a été atteint, celui-ci a donc été supprimé :"
other: "Le délai maximum de conservation des dossiers en brouillon suivants a été atteint, ceux-ci ont donc été supprimés :"
one: "Le délai maximum de conservation du dossier en brouillon a été atteint, celui-ci a donc été supprimé :"
other: "Le délai maximum de conservation des dossiers en brouillon a été atteint, ceux-ci ont donc été supprimés :"

View file

@ -5,8 +5,8 @@ fr:
one: Un dossier en brouillon va bientôt être supprimé
other: Des dossiers en brouillon vont bientôt être supprimés
header:
one: "Afin de limiter la conservation de vos données personnelles, le dossier en brouillon suivant sera bientôt automatiquement supprimé :"
other: "Afin de limiter la conservation de vos données personnelles, les dossiers en brouillon suivants seront bientôt automatiquement supprimés :"
footer:
one: "Si vous souhaitez toujours déposer ce dossier, vous pouvez retrouver votre brouillon pendant encore <b>un mois</b>. Si vous souhaitez conserver votre dossier plus longtemps, vous pouvez <b>prolonger sa durée de conservation</b> dans linterface. Et sinon, vous navez rien à faire."
other: "Si vous souhaitez toujours déposer ces dossiers, vous pouvez retrouver vos brouillons pendant encore <b>un mois</b>. Si vous souhaitez conserver vos dossiers plus longtemps, vous pouvez <b>prolonger leur durée de conservation</b> au cas par cas dans linterface. Et sinon, vous navez rien à faire."
one: "Afin de limiter la conservation de vos données personnelles, ce dossier en brouillon sera bientôt supprimé :"
other: "Afin de limiter la conservation de vos données personnelles, ces dossiers en brouillon seront bientôt supprimés :"
account_active:
one: Votre compte reste activé sur Démarches Simplifiées, seul le dossier sera supprimé.
other: Votre compte reste activé sur Démarches Simplifiées, seuls les dossiers seront supprimés.

View file

@ -2,20 +2,15 @@ fr:
dossier_mailer:
notify_near_deletion_to_administration:
subject_en_construction:
one: Un dossier en construction va bientôt être supprimé
other: Des dossiers en construction vont bientôt être supprimés
one: Un dossier en attente d'instruction va bientôt être supprimé
other: Des dossiers en attente d'instruction 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
one: Un dossier traité va bientôt être supprimé
other: Des dossiers traités 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 suivants seront bientôt automatiquement supprimés :"
one: "il vous reste %{remaining_weeks_before_expiration} pour démarrer l'instruction de ce dossier avant qu'il ne soit supprimé :"
other: "il vous reste %{remaining_weeks_before_expiration} pour démarrer l'instruction de ces dossiers avant qu'ils ne soient supprimés :"
header_termine:
one: "Le dossier suivant dont le traitement est terminé sera bientôt automatiquement supprimé :"
other: "Les dossiers suivants dont le traitement est terminé seront bientôt automatiquement supprimés :"
footer_en_construction:
one: "Vous avez <b>%{remaining_weeks_before_expiration}</b> pour commencer linstruction du dossier."
other: "Vous avez <b>%{remaining_weeks_before_expiration}</b> pour commencer linstruction des dossiers."
footer_termine:
one: "Vous avez <b>%{remaining_weeks_before_expiration}</b> pour archiver le dossier."
other: "Vous avez <b>%{remaining_weeks_before_expiration}</b> pour archiver les dossiers."
one: "il vous reste %{remaining_weeks_before_expiration} pour archiver ce dossier traité avant qu'il ne soit supprimé :"
other: "il vous reste %{remaining_weeks_before_expiration} pour archiver ces dossier traités avant qu'ils ne soient supprimés :"
footer_en_construction: Vous pouvez tenir informé l'usager, en utilisant la messagerie depuis la page du dossier.

View file

@ -2,23 +2,23 @@ fr:
dossier_mailer:
notify_near_deletion_to_user:
subject_en_construction:
one: Un dossier en construction va bientôt être supprimé
other: Des dossiers en construction vont bientôt être supprimés
one: Un dossier en attente d'instruction va bientôt être supprimé
other: Des dossiers en attente d'instruction 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
one: Un dossier traité va bientôt être supprimé
other: Des dossiers traités vont bientôt être supprimés
header_en_construction:
one: "Afin de respecter la durée de conservation de vos données personnelles, le dossier en construction suivant sera supprimé automatiquement dans deux semaines :"
other: "Afin de respecter la durée de conservation de vos données personnelles, les dossiers en construction suivants seront supprimés automatiquement dans deux semaines :"
one: "Afin de respecter la durée de conservation de vos données personnelles, le dossier en attente d'instruction suivant sera supprimé automatiquement dans deux semaines :"
other: "Afin de respecter la durée de conservation de vos données personnelles, les dossiers en attente d'instruction suivants seront supprimés automatiquement dans deux semaines :"
header_termine:
one: "Afin de respecter la durée de conservation de vos données personnelles, le dossier suivant dont le traitement est terminé sera supprimé automatiquement dans deux semaines :"
other: "Afin de respecter la durée de conservation de vos données personnelles, les dossiers suivants dont le traitement est terminé seront supprimés automatiquement dans deux semaines :"
one: "Afin de respecter la durée de conservation de vos données personnelles, ce dossier traité sera supprimé dans deux semaines :"
other: "Afin de respecter la durée de conservation de vos données personnelles, ces dossiers traités seront supprimés dans deux semaines :"
account_active:
one: Votre compte reste activé sur Démarches Simplifiées, seul le dossier sera supprimé.
other: Votre compte reste activé sur Démarches Simplifiées, seuls les dossiers seront supprimés.
footer_termine:
one: "Vous pouvez télécharger votre dossier au format PDF depuis longlet « Expirant » sur la page <a href=\"%{dossiers_url}\">Mes dossiers</a>."
other: "Vous pouvez télécharger vos dossiers au format PDF depuis longlet « Expirant » sur la page <a href=\"%{dossiers_url}\">Mes dossiers</a>."
one: Vous pouvez télécharger votre dossier au format PDF depuis longlet « Expirant » sur la page
other: "Vous pouvez télécharger vos dossiers au format PDF depuis longlet « Expirant » sur la page "
footer_en_construction:
one: "Si vous souhaitez conserver votre dossier plus longtemps, vous pouvez <b>prolonger sa durée de conservation</b> dans linterface."
other: "Si vous souhaitez conserver vos dossiers plus longtemps, vous pouvez <b>prolonger leur durée de conservation</b> au cas par cas dans linterface."
one: Depuis la page de votre dossier vous avez la possibilité de :<br>- prolonger la durée de conservation<br>- contacter l'administration qui gère votre dossier via la messagerie
other: Depuis la page de vos dossiers vous avez la possibilité de :<br>- prolonger la durée de conservation<br>- contacter l'administration qui gère votre dossier via la messagerie

View file

@ -5,10 +5,11 @@ fr:
banner:
expiration_date_extended: " la date de conservation a déjà été étendue"
title: Ce dossier va expirer
title_expired: Ce dossier a expiré
states:
brouillon: "" # not applicable, instructeur does not see brouillons
en_construction: Ce dossier est en attente de prise en charge. Vous pouvez toutefois étendre cette durée dun mois en cliquant sur le bouton suivant.
termine: Le traitement de ce dossier est terminé, mais il va bientôt expirer. Cela signifie quil va bientôt être supprimé. Si vous souhaitez en conserver une trace, vous pouvez le télécharger au format PDF.
termine: Le traitement de ce dossier est terminé, mais il va bientôt être supprimé. Si vous souhaitez en conserver une trace, vous pouvez le télécharger au format PDF.
button_delay_expiration: "Conserver un mois de plus"
notification_management: gestion des notifications
administrators_list: voir les administrateurs

View file

@ -12,10 +12,11 @@ fr:
new_procedure_content: "Une nouvelle démarche est disponible, consultez-la ici :"
contact_service_html: Pour plus dinformations, veuillez vous rapprocher du service %{service_name}, disponible au %{service_phone_number} ou par email à <a href="mailto:%{service_email}">%{service_email}</a>
title: Votre dossier va expirer
title_expired: Votre dossier a expiré
states:
brouillon: Votre dossier est en brouillon, mais va bientôt expirer. Cela signifie quil va bientôt être supprimé sans avoir été déposé. Si vous souhaitez le conserver afin de poursuivre la démarche, vous pouvez étendre la durée de conversation en cliquant sur le bouton ci-dessous.
brouillon: Votre dossier est en brouillon, mais va bientôt être supprimé sans avoir été déposé. Si vous souhaitez le conserver afin de poursuivre la démarche, vous pouvez étendre la durée de conversation en cliquant sur le bouton ci-dessous.
en_construction: Votre dossier est en attente de prise en charge par ladministration. Le délai de prise en charge maximal est de %{nominal_duration_months} mois. Vous pouvez toutefois étendre cette durée en cliquant sur le bouton ci-dessous.
termine: Le traitement de votre dossier est terminé, mais il va bientôt expirer. Cela signifie quil va bientôt être supprimé. Si vous souhaitez en conserver une trace, vous pouvez le télécharger au format PDF.
termine: Le traitement de votre dossier est terminé, mais il va bientôt être supprimé. Si vous souhaitez en conserver une trace, vous pouvez le télécharger au format PDF.
button_delay_expiration:
one: "Conserver %{count} mois supplémentaire"
other: "Conserver %{count} mois supplémentaires"

View file

@ -268,6 +268,7 @@ Rails.application.routes.draw do
get '/carte' => 'carte#show'
post '/carte' => 'carte#save'
post '/repousser-expiration' => 'dossiers#extend_conservation'
post '/repousser-expiration-and-restore' => 'dossiers#extend_conservation_and_restore'
end
# Redirection of legacy "/users/dossiers" route to "/dossiers"
@ -489,6 +490,7 @@ Rails.application.routes.draw do
member do
resources :commentaires, only: [:destroy]
post 'repousser-expiration' => 'dossiers#extend_conservation'
post 'repousser-expiration-and-restore' => 'dossiers#extend_conservation_and_restore'
get 'geo_data'
get 'apercu_attestation'
get 'bilans_bdf'

View file

@ -0,0 +1,5 @@
class AddHiddenByExpiredAtToDossiers < ActiveRecord::Migration[7.0]
def change
add_column :dossiers, :hidden_by_expired_at, :datetime
end
end

View file

@ -469,6 +469,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_07_16_091043) do
t.datetime "groupe_instructeur_updated_at", precision: nil
t.datetime "hidden_at", precision: nil
t.datetime "hidden_by_administration_at", precision: nil
t.datetime "hidden_by_expired_at"
t.string "hidden_by_reason"
t.datetime "hidden_by_user_at", precision: nil
t.datetime "identity_updated_at", precision: nil

View file

@ -1307,6 +1307,71 @@ describe Instructeurs::DossiersController, type: :controller do
end
end
describe '#extend_conservation and restore' do
subject { post :extend_conservation_and_restore, params: { procedure_id: procedure.id, dossier_id: dossier.id } }
before do
dossier.update(hidden_by_expired_at: 1.hour.ago, hidden_by_reason: 'expired')
end
context 'when dossier has expired but was not hidden by anyone' do
it 'works' do
expect(subject).to redirect_to(instructeur_dossier_path(procedure, dossier))
end
it 'extends conservation_extension by 1 month and let dossier not hidden' do
subject
expect(dossier.reload.conservation_extension).to eq(1.month)
expect(dossier.reload.hidden_by_reason).to eq(nil)
expect(dossier.reload.hidden_by_expired_at).to eq(nil)
expect(dossier.reload.hidden_by_administration_at).to eq(nil)
expect(dossier.reload.hidden_by_user_at).to eq(nil)
end
it 'flashed notice success' do
subject
expect(flash[:notice]).to eq(I18n.t('views.instructeurs.dossiers.archived_dossier'))
end
end
context 'when dossier has expired and was hidden by instructeur' do
let!(:dossier) { create(:dossier, :hidden_by_administration, :accepte, :with_individual, procedure: procedure) }
it 'extends conservation_extension by 1 month and restore dossier for instructeur' do
subject
expect(dossier.reload.conservation_extension).to eq(1.month)
expect(dossier.reload.hidden_by_reason).to eq(nil)
expect(dossier.reload.hidden_by_expired_at).to eq(nil)
expect(dossier.reload.hidden_by_administration_at).to eq(nil)
expect(dossier.reload.hidden_by_user_at).to eq(nil)
end
end
context 'when dossier has expired and was hidden by user' do
let!(:dossier) { create(:dossier, :hidden_by_user, :accepte, :with_individual, procedure: procedure) }
it 'extends conservation_extension by 1 month and let dossier hidden for user' do
subject
expect(dossier.reload.conservation_extension).to eq(1.month)
expect(dossier.reload.hidden_by_reason).to eq("user_request")
expect(dossier.reload.hidden_by_expired_at).to eq(nil)
expect(dossier.reload.hidden_by_administration_at).to eq(nil)
expect(dossier.reload.hidden_by_user_at).not_to eq(nil)
end
end
context 'when dossier has expired and was hidden by user and instructeur' do
let!(:dossier) { create(:dossier, :hidden_by_user, :hidden_by_administration, :accepte, :with_individual, procedure: procedure) }
it 'extends conservation_extension by 1 month and let dossier hidden for user' do
subject
expect(dossier.reload.conservation_extension).to eq(1.month)
expect(dossier.reload.hidden_by_reason).to eq("user_request")
expect(dossier.reload.hidden_by_expired_at).to eq(nil)
expect(dossier.reload.hidden_by_administration_at).to eq(nil)
expect(dossier.reload.hidden_by_user_at).not_to eq(nil)
end
end
end
describe '#reaffectation' do
let!(:gi_2) { GroupeInstructeur.create(label: 'deuxième groupe', procedure: procedure) }
let!(:gi_3) { GroupeInstructeur.create(label: 'troisième groupe', procedure: procedure) }

View file

@ -114,6 +114,16 @@ FactoryBot.define do
hidden_at { Time.zone.now }
end
trait :hidden_by_expired do
hidden_by_expired_at { 1.day.ago }
hidden_by_reason { DeletedDossier.reasons.fetch(:expired) }
end
trait :hidden_by_user do
hidden_by_user_at { 1.day.ago }
hidden_by_reason { DeletedDossier.reasons.fetch(:user_request) }
end
trait :hidden_by_administration do
hidden_by_administration_at { 1.day.ago }
hidden_by_reason { DeletedDossier.reasons.fetch(:instructeur_request) }

View file

@ -2,6 +2,7 @@ RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
describe '#perform' do
let(:instructeur) { create(:instructeur) }
let(:dossier) { create(:dossier, :with_individual, state) }
let(:dossier_2) { create(:dossier, :with_individual, state) }
before do
# hack to add passer_en_instruction and supprimer to dossier.dossier_operation_logs
@ -9,6 +10,8 @@ RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
dossier.send(:log_dossier_operation, instructeur, :supprimer, dossier)
dossier.update_columns(hidden_by_user_at: hidden_at, hidden_by_administration_at: hidden_at)
dossier.update_column(:hidden_by_reason, "user_request")
dossier_2.update_columns(hidden_by_expired_at: hidden_at)
dossier_2.update_column(:hidden_by_reason, "expired")
end
subject do
@ -24,6 +27,7 @@ RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
it 'does not delete it' do
expect { dossier.reload }.not_to raise_error
expect { dossier_2.reload }.not_to raise_error
end
it 'does not delete its operations logs' do
@ -36,6 +40,7 @@ RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
it 'does delete it' do
expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect { dossier_2.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'deletes its operations logs except supprimer' do

View file

@ -84,23 +84,23 @@ RSpec.describe DossierMailer, type: :mailer do
it { expect(subject.perform_deliveries).to be_falsy }
end
def notify_deletion_to_administration(deleted_dossier, to_email)
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
@deleted_dossier = deleted_dossier
def notify_deletion_to_administration(hidden_dossier, to_email)
@subject = default_i18n_subject(dossier_id: hidden_dossier.id)
@hidden_dossier = hidden_dossier
mail(to: to_email, subject: @subject)
end
describe '.notify_deletion_to_administration' do
let(:deleted_dossier) { build(:deleted_dossier) }
let(:hidden_dossier) { build(:dossier) }
subject { described_class.notify_deletion_to_administration(deleted_dossier, to_email) }
subject { described_class.notify_deletion_to_administration(hidden_dossier, to_email) }
it 'verifies subject and body content for deletion notification' do
expect(subject.subject).to eq("Le dossier nº #{deleted_dossier.dossier_id} a été supprimé à la demande de lusager")
expect(subject.subject).to eq("Le dossier nº #{hidden_dossier.id} a été supprimé à la demande de lusager")
expect(subject.body).to include("À la demande de lusager")
expect(subject.body).to include(deleted_dossier.dossier_id)
expect(subject.body).to include(deleted_dossier.procedure.libelle)
expect(subject.body).to include(hidden_dossier.id)
expect(subject.body).to include(hidden_dossier.procedure.libelle)
end
end
@ -121,52 +121,53 @@ RSpec.describe DossierMailer, type: :mailer do
subject { described_class.notify_brouillon_deletion([dossier.hash_for_deletion_mail], dossier.user.email) }
it 'verifies subject and body content for brouillon deletion notification' do
expect(subject.subject).to eq("Un dossier en brouillon a été supprimé automatiquement")
expect(subject.subject).to eq("Un dossier en brouillon a été supprimé")
expect(subject.body).to include(" #{dossier.id} (#{dossier.procedure.libelle})")
end
end
describe '.notify_automatic_deletion_to_user' do
let(:deleted_dossier) { create(:deleted_dossier, dossier: dossier, reason: :expired) }
# let(:deleted_dossier) { create(:deleted_dossier, dossier: dossier, reason: :expired) }
# let(:hidden_dossier) { build(:dossier, :en_construction, hidden_at: Time.zone.now, hidden_by_reason: 'expired') }
describe 'en_construction' do
let(:dossier) { create(:dossier, :en_construction) }
# let(:dossier) { create(:dossier, :en_construction) }
let(:hidden_dossier) { create(:dossier, :en_construction, hidden_at: Time.zone.now, hidden_by_reason: 'expired') }
subject { described_class.notify_automatic_deletion_to_user([deleted_dossier], dossier.user.email) }
subject { described_class.notify_automatic_deletion_to_user([hidden_dossier], hidden_dossier.user.email) }
it 'checks email subject, to, and body for correct inclusions and exclusions for en_construction status' do
expect(subject.to).to eq([dossier.user.email])
expect(subject.subject).to eq("Un dossier a été supprimé automatiquement de votre compte")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
expect(subject.body).to include("nous nous excusons de la gêne occasionnée")
expect(subject.to).to eq([hidden_dossier.user.email])
expect(subject.subject).to eq("Un dossier a été supprimé de votre compte")
expect(subject.body).to include("#{hidden_dossier.id} ")
expect(subject.body).to include(hidden_dossier.procedure.libelle)
end
end
describe 'termine' do
let(:dossier) { create(:dossier, :accepte) }
let(:hidden_dossier) { create(:dossier, :accepte, hidden_at: Time.zone.now, hidden_by_reason: 'expired') }
subject { described_class.notify_automatic_deletion_to_user([deleted_dossier], dossier.user.email) }
subject { described_class.notify_automatic_deletion_to_user([hidden_dossier], hidden_dossier.user.email) }
it 'checks email subject, to, and body for correct inclusions and exclusions for termine status' do
expect(subject.to).to eq([dossier.user.email])
expect(subject.subject).to eq("Un dossier a été supprimé automatiquement de votre compte")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
expect(subject.body).not_to include("nous nous excusons de la gêne occasionnée")
expect(subject.to).to eq([hidden_dossier.user.email])
expect(subject.subject).to eq("Un dossier a été supprimé de votre compte")
expect(subject.body).to include("#{hidden_dossier.id} ")
expect(subject.body).to include(hidden_dossier.procedure.libelle)
end
end
end
describe '.notify_automatic_deletion_to_administration' do
let(:dossier) { create(:dossier, :en_construction) }
let(:deleted_dossier) { create(:deleted_dossier, dossier: dossier, reason: :expired) }
# let(:dossier) { create(:dossier, :en_construction) }
let(:hidden_dossier) { create(:dossier, :accepte, hidden_at: Time.zone.now, hidden_by_reason: 'expired') }
# let(:deleted_dossier) { create(:deleted_dossier, dossier: dossier, reason: :expired) }
subject { described_class.notify_automatic_deletion_to_administration([deleted_dossier], dossier.user.email) }
subject { described_class.notify_automatic_deletion_to_administration([hidden_dossier], hidden_dossier.user.email) }
it 'verifies subject and body content for automatic deletion notification' do
expect(subject.subject).to eq("Un dossier a été supprimé automatiquement")
expect(subject.body).to include("#{dossier.id} (#{dossier.procedure.libelle})")
expect(subject.subject).to eq("Un dossier a été supprimé")
expect(subject.body).to include("#{hidden_dossier.id} (#{hidden_dossier.procedure.libelle})")
end
end
@ -177,11 +178,11 @@ RSpec.describe DossierMailer, type: :mailer do
subject { described_class.notify_near_deletion_to_administration([dossier], dossier.user.email) }
it 'checks email subject and body for correct inclusions for en_construction status' do
expect(subject.subject).to eq("Un dossier en construction va bientôt être supprimé")
expect(subject.subject).to eq("Un dossier en attente d'instruction va bientôt être supprimé")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
expect(subject.body).to include("PDF")
expect(subject.body).to include("Vous avez <b>14 jours</b> pour commencer linstruction du dossier.")
expect(subject.body).to include("il vous reste 14 jours pour démarrer l&#39;instruction ")
end
end
@ -191,7 +192,7 @@ RSpec.describe DossierMailer, type: :mailer do
subject { described_class.notify_near_deletion_to_administration([dossier], dossier.user.email) }
it 'verifies subject and body content for near deletion notification of completed cases' do
expect(subject.subject).to eq("Un dossier dont le traitement est terminé va bientôt être supprimé")
expect(subject.subject).to eq("Un dossier traité va bientôt être supprimé")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
end
@ -206,11 +207,11 @@ RSpec.describe DossierMailer, type: :mailer do
it 'verifies email subject, to, and body for correct inclusions for en_construction status' do
expect(subject.to).to eq([dossier.user.email])
expect(subject.subject).to eq("Un dossier en construction va bientôt être supprimé")
expect(subject.subject).to eq("Un dossier en attente d'instruction va bientôt être supprimé")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
expect(subject.body).to include("Votre compte reste activé")
expect(subject.body).to include("Si vous souhaitez conserver votre dossier plus longtemps, vous pouvez <b>prolonger sa durée de conservation</b> dans linterface.")
expect(subject.body).to include("Depuis la page de votre dossier vous avez la possibilité de :<br>- prolonger la durée de conservation")
end
end
@ -221,7 +222,7 @@ RSpec.describe DossierMailer, type: :mailer do
it 'checks email subject, to, and body for correct inclusions for termine status' do
expect(subject.to).to eq([dossier.user.email])
expect(subject.subject).to eq("Un dossier dont le traitement est terminé va bientôt être supprimé")
expect(subject.subject).to eq("Un dossier traité va bientôt être supprimé")
expect(subject.body).to include("#{dossier.id} ")
expect(subject.body).to include(dossier.procedure.libelle)
expect(subject.body).to include("Votre compte reste activé")
@ -235,7 +236,7 @@ RSpec.describe DossierMailer, type: :mailer do
subject { described_class.notify_near_deletion_to_user(dossiers, dossiers[0].user.email) }
it 'verifies email subject and body contain correct dossier numbers for multiple termine status' do
expect(subject.subject).to eq("Des dossiers dont le traitement est terminé vont bientôt être supprimés")
expect(subject.subject).to eq("Des dossiers traités vont bientôt être supprimés")
dossiers.each do |dossier|
expect(subject.body).to include("#{dossier.id} ")
end

View file

@ -56,15 +56,15 @@ class DossierMailerPreview < ActionMailer::Preview
end
def notify_deletion_to_administration
DossierMailer.notify_deletion_to_administration(deleted_dossier, administration_email)
DossierMailer.notify_deletion_to_administration(dossier, administration_email)
end
def notify_automatic_deletion_to_user
DossierMailer.notify_automatic_deletion_to_user([deleted_dossier, deleted_dossier], usager_email)
DossierMailer.notify_automatic_deletion_to_user([dossier, dossier], usager_email)
end
def notify_automatic_deletion_to_administration
DossierMailer.notify_automatic_deletion_to_administration([deleted_dossier, deleted_dossier], administration_email)
DossierMailer.notify_automatic_deletion_to_administration([dossier, dossier], administration_email)
end
def notify_brouillon_not_submitted

View file

@ -724,6 +724,7 @@ describe Instructeur, type: :model do
it { expect(subject['traites']).to eq(0) }
it { expect(subject['tous']).to eq(0) }
it { expect(subject['archives']).to eq(1) }
it { expect(subject['supprimes_recemment']).to eq(0) }
it { expect(subject['expirant']).to eq(0) }
context 'and terminer dossiers on each of the others groups' do
@ -736,6 +737,7 @@ describe Instructeur, type: :model do
context 'with an expirants dossier' do
let!(:expiring_dossier_termine_deleted) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago, hidden_by_administration_at: 2.days.ago) }
let!(:expiring_dossier_termine_auto_deleted) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago, hidden_by_expired_at: 2.days.ago) }
let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) }
let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, en_construction_at: 175.days.ago, procedure: procedure) }
before { subject }
@ -745,6 +747,7 @@ describe Instructeur, type: :model do
it { expect(subject['traites']).to eq(1) }
it { expect(subject['tous']).to eq(2) }
it { expect(subject['archives']).to eq(0) }
it { expect(subject['supprimes_recemment']).to eq(2) }
it { expect(subject['expirant']).to eq(2) }
end
end

View file

@ -217,7 +217,6 @@ describe Expired::DossiersDeletionService do
context 'with a single dossier' do
let!(:dossier) { create(:dossier, :en_construction, :followed, procedure: procedure, en_construction_close_to_expiration_notice_sent_at: notice_sent_at) }
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
before { service.delete_expired_en_construction_and_notify }
@ -240,22 +239,23 @@ describe Expired::DossiersDeletionService do
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_user).with([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) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier], dossier.procedure.administrateurs.first.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier], dossier.followers_instructeurs.first.email) }
it { expect(dossier.reload.hidden_by_user_at).to eq(nil) }
it { expect(dossier.reload.hidden_by_administration_at).to eq(nil) }
it { expect(dossier.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier.reload.hidden_by_reason).to eq('expired') }
end
end
context 'with 2 dossiers to delete' do
let!(:dossier_1) { create(:dossier, :en_construction, procedure: procedure, user: user, en_construction_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) }
let!(:dossier_2) { create(:dossier, :en_construction, procedure: procedure_2, user: user, en_construction_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) }
@ -265,12 +265,17 @@ describe Expired::DossiersDeletionService do
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_user).with(match_array([dossier_1, 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) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with(match_array([dossier_1, dossier_2]), instructeur.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier_1], dossier_1.procedure.administrateurs.first.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier_2], dossier_2.procedure.administrateurs.first.email) }
it { expect(dossier_1.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier_1.reload.hidden_by_reason).to eq('expired') }
it { expect(dossier_2.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier_2.reload.hidden_by_reason).to eq('expired') }
end
end
@ -364,7 +369,6 @@ describe Expired::DossiersDeletionService do
context 'with a single dossier' do
let!(:dossier) { create(:dossier, :followed, :accepte, procedure: procedure, termine_close_to_expiration_notice_sent_at: notice_sent_at) }
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
before { service.delete_expired_termine_and_notify }
@ -387,22 +391,21 @@ describe Expired::DossiersDeletionService do
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(dossier.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier.reload.hidden_by_reason).to eq('expired') }
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_user).with([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) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier], dossier.procedure.administrateurs.first.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([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) }
@ -412,19 +415,22 @@ describe Expired::DossiersDeletionService do
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_user).with(match_array([dossier_1, 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) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with(match_array([dossier_1, dossier_2]), instructeur.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier_1], dossier_1.procedure.administrateurs.first.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier_2], dossier_2.procedure.administrateurs.first.email) }
it { expect(dossier_1.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier_1.reload.hidden_by_reason).to eq('expired') }
it { expect(dossier_2.reload.hidden_by_expired_at).to be_an_instance_of(ActiveSupport::TimeWithZone) }
it { expect(dossier_2.reload.hidden_by_reason).to eq('expired') }
end
context 'with 1 dossier deleted by user and 1 dossier deleted by administration' do
let!(:dossier_1) { create(:dossier, :accepte, procedure: procedure, user: user, hidden_by_administration_at: 1.hour.ago, termine_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) }
let!(:dossier_2) { create(:dossier, :refuse, procedure: procedure_2, user: user, hidden_by_user_at: 1.hour.ago, 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) }
@ -434,11 +440,11 @@ describe Expired::DossiersDeletionService do
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]), user.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).with(match_array([dossier_1]), 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(match_array([deleted_dossier_2]), instructeur.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_2], dossier_2.procedure.administrateurs.first.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with(match_array([dossier_2]), instructeur.email) }
it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([dossier_2], dossier_2.procedure.administrateurs.first.email) }
end
end
end

View file

@ -294,13 +294,13 @@ describe 'The user' do
login_as(user, scope: :user)
visit brouillon_dossier_path(user_old_dossier)
expect(page).to have_css('.fr-callout__title', text: 'Votre dossier va expirer', visible: true)
expect(page).to have_css('.fr-callout__title', text: 'Votre dossier a expiré', visible: true)
find('#test-user-repousser-expiration').click
expect(page).to have_no_selector('#test-user-repousser-expiration')
Timecop.freeze(simple_procedure.duree_conservation_dossiers_dans_ds.month.from_now) do
visit brouillon_dossier_path(user_old_dossier)
expect(page).to have_css('.fr-callout__title', text: 'Votre dossier va expirer', visible: true)
expect(page).to have_css('.fr-callout__title', text: 'Votre dossier a expiré', visible: true)
find('#test-user-repousser-expiration').click
expect(page).to have_no_selector('#test-user-repousser-expiration')
end

View file

@ -12,6 +12,9 @@ describe 'user access to the list of their dossiers', js: true do
let!(:dossier_for_tiers) { create(:dossier, :en_instruction, :for_tiers_with_notification, user: user) }
let!(:dossier_en_construction_with_accuse_lecture) { create(:dossier, :en_construction, user: user, procedure: procedure_accuse_lecture) }
let!(:dossier_accepte_with_accuse_lecture) { create(:dossier, :accepte, user: user, procedure: procedure_accuse_lecture) }
let!(:dossier_en_construction_expire) { create(:dossier, :with_individual, :with_populated_champs, :en_construction, :hidden_by_expired, user: user) }
let!(:dossier_traite_expire) { create(:dossier, :accepte, :hidden_by_expired, user: user) }
let!(:dossier_en_construction_supprime) { create(:dossier, :with_individual, :with_populated_champs, :en_construction, :hidden_by_user, user: user) }
let(:dossiers_per_page) { 25 }
let(:last_updated_dossier) { dossier_en_construction }
@ -193,23 +196,54 @@ describe 'user access to the list of their dossiers', js: true do
expect(page).not_to have_content(dossier_en_construction.procedure.libelle)
end
end
end
describe 'clone' do
it 'should have links to clone dossiers' do
expect(page).to have_link(nil, href: clone_dossier_path(dossier_brouillon))
expect(page).to have_link(nil, href: clone_dossier_path(dossier_en_construction))
expect(page).to have_link(nil, href: clone_dossier_path(dossier_en_instruction))
end
describe 'clone' do
it 'should have links to clone dossiers' do
expect(page).to have_link(nil, href: clone_dossier_path(dossier_brouillon))
expect(page).to have_link(nil, href: clone_dossier_path(dossier_en_construction))
expect(page).to have_link(nil, href: clone_dossier_path(dossier_en_instruction))
end
context 'when user clicks on clone button', js: true do
scenario 'the dossier is cloned' do
within(:css, ".card", match: :first) do
click_on 'Autres actions'
expect { click_on 'Dupliquer ce dossier' }.to change { dossier_brouillon.user.dossiers.count }.by(1)
end
expect(page).to have_content("Votre dossier a bien été dupliqué. Vous pouvez maintenant le vérifier, ladapter puis le déposer.")
context 'when user clicks on clone button', js: true do
scenario 'the dossier is cloned' do
within(:css, ".card", match: :first) do
click_on 'Autres actions'
expect { click_on 'Dupliquer ce dossier' }.to change { dossier_brouillon.user.dossiers.count }.by(1)
end
expect(page).to have_content("Votre dossier a bien été dupliqué. Vous pouvez maintenant le vérifier, ladapter puis le déposer.")
end
end
end
describe 'restore' do
it 'should have links to restore dossiers' do
click_on "3 supprimés récemment"
expect(page).to have_link('Restaurer', href: restore_dossier_path(dossier_en_construction_supprime))
expect(page).to have_button('Restaurer et étendre la conservation')
expect(page).to have_link('Télécharger mon dossier', href: dossier_path("#{dossier_traite_expire.id}.pdf"))
end
context 'when user clicks on restore button', js: true do
scenario 'the dossier is restored' do
click_on "3 supprimés récemment"
expect(page).to have_content(dossier_en_construction_supprime.procedure.libelle)
click_on 'Restaurer'
expect(page).to have_content('Votre dossier a bien été restauré')
expect(page).to have_content('2 supprimés récemment')
end
end
context 'when user clicks on restore and extend button', js: true do
scenario 'the dossier is restored and extended' do
click_on "3 supprimés récemment"
expect(page).to have_content(dossier_en_construction_expire.procedure.libelle)
click_on 'Restaurer et étendre la conservation'
expect(page).to have_content('Votre dossier sera conservé 3 mois supplémentaire')
expect(page).to have_content('2 supprimés récemment')
end
end
end

View file

@ -147,7 +147,7 @@ describe 'users/dossiers/index', type: :view do
expect(rendered).to have_text(/6\s+en cours/)
end
it "cache key dpeends on dossier invites" do
it "cache key depends on dossier invites" do
expect(user_dossiers).to receive(:present?).twice
render
@ -161,7 +161,7 @@ describe 'users/dossiers/index', type: :view do
expect(user_dossiers).to receive(:present?).twice
render
dossier_termine.expired_keep_track_and_destroy!
dossier_termine.hide_and_keep_track!(:automatic, :expired)
user.reload
render