Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[usager] Laisser un délai avant suppression des dossiers expirés #10488

Merged
merged 17 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/controllers/instructeurs/dossiers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ def extend_conservation
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',
Expand Down Expand Up @@ -376,6 +382,10 @@ def dossier_scope
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
Expand Down
10 changes: 9 additions & 1 deletion app/controllers/users/dossiers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def index
@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
Expand Down Expand Up @@ -259,6 +259,12 @@ def extend_conservation
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
Expand Down Expand Up @@ -530,6 +536,8 @@ def dossier_scope
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
Expand Down
22 changes: 11 additions & 11 deletions app/mailers/dossier_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,32 +129,32 @@ def notify_en_construction_deletion_to_administration(dossier, to_email)
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merci d'avoir renommé !

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
Expand Down
74 changes: 47 additions & 27 deletions app/models/dossier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,12 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon
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) }
Expand Down Expand Up @@ -363,12 +365,12 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon
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'
Expand Down Expand Up @@ -415,7 +417,7 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon
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'
Expand Down Expand Up @@ -600,6 +602,10 @@ def can_be_deleted_by_administration?(reason)
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
Expand Down Expand Up @@ -645,7 +651,12 @@ def expiration_notification_date

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
Expand Down Expand Up @@ -677,6 +688,12 @@ def extend_conservation(conservation_extension)
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
Expand Down Expand Up @@ -766,6 +783,10 @@ def log_operations?
!procedure.brouillon? && !brouillon?
end

def hidden_by_expired?
hidden_by_expired_at.present?
end

def hidden_by_user?
hidden_by_user_at.present?
end
Expand Down Expand Up @@ -820,37 +841,32 @@ def build_attestation
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?
Expand All @@ -863,14 +879,18 @@ def hide_and_keep_track!(author, reason)

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)
Expand Down
16 changes: 8 additions & 8 deletions app/models/instructeur.rb
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,18 @@ def flipper_id
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
Expand Down
8 changes: 5 additions & 3 deletions app/services/dossier_projection_service.rb
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

@tchak tchak Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je pense qu'il faut ajouter ici hidden_by_user_at

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu veux dire hidden_by_expired_at ? Et je laisse l'ajout de la colonne hidden_by_reasonou pas nécessaire ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ca me va de conserver la hidden_by_reason

def pending_correction?
return false if corrections.blank?

Expand Down Expand Up @@ -44,13 +44,14 @@ def self.project(dossiers_ids, fields)
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|
Expand All @@ -73,7 +74,7 @@ def self.project(dossiers_ids, fields)
.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
Expand Down Expand Up @@ -150,6 +151,7 @@ def self.project(dossiers_ids, fields)
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],
Expand Down
15 changes: 7 additions & 8 deletions app/services/expired/dossiers_deletion_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,26 @@ def delete_expired_and_notify(dossiers_to_remove, notify_on_closed_procedures_to
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)
Expand Down
Loading
Loading