Merge pull request #5750 from betagouv/feat/5720
feat/5720 - EQT instructeur, je peux supprimer un dossier terminé
This commit is contained in:
commit
1fe1fa7a98
27 changed files with 410 additions and 116 deletions
|
@ -214,6 +214,17 @@ module Instructeurs
|
|||
zipline(files, "dossier-#{dossier.id}.zip")
|
||||
end
|
||||
|
||||
def delete_dossier
|
||||
if dossier.termine?
|
||||
dossier.discard_and_keep_track!(current_instructeur, :instructeur_request)
|
||||
flash.notice = 'Le dossier a bien été supprimé'
|
||||
redirect_to instructeur_procedure_path(procedure)
|
||||
else
|
||||
flash.alert = "Suppression impossible : le dossier n'est pas terminé"
|
||||
redirect_back(fallback_location: instructeur_procedures_url)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def dossier
|
||||
|
|
|
@ -18,15 +18,8 @@ module Users
|
|||
def index
|
||||
@user_dossiers = current_user.dossiers.includes(:procedure).order_by_updated_at.page(page)
|
||||
@dossiers_invites = current_user.dossiers_invites.includes(:procedure).order_by_updated_at.page(page)
|
||||
|
||||
@current_tab = current_tab(@user_dossiers.count, @dossiers_invites.count)
|
||||
|
||||
@dossiers = case @current_tab
|
||||
when 'mes-dossiers'
|
||||
@user_dossiers
|
||||
when 'dossiers-invites'
|
||||
@dossiers_invites
|
||||
end
|
||||
@dossiers_supprimes = current_user.deleted_dossiers.order_by_updated_at.page(page)
|
||||
@statut = statut(@user_dossiers, @dossiers_invites, @dossiers_supprimes, params[:statut])
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -282,6 +275,25 @@ module Users
|
|||
|
||||
private
|
||||
|
||||
# if the status tab is filled, then this tab
|
||||
# else first filled tab
|
||||
# else mes-dossiers
|
||||
def statut(mes_dossiers, dossiers_invites, dossiers_supprimes, params_statut)
|
||||
tabs = {
|
||||
'mes-dossiers' => mes_dossiers.present?,
|
||||
'dossiers-invites' => dossiers_invites.present?,
|
||||
'dossiers-supprimes' => dossiers_supprimes.present?
|
||||
}
|
||||
if tabs[params_statut]
|
||||
params_statut
|
||||
else
|
||||
tabs
|
||||
.filter { |_tab, filled| filled }
|
||||
.map { |tab, _| tab }
|
||||
.first || 'mes-dossiers'
|
||||
end
|
||||
end
|
||||
|
||||
def store_user_location!
|
||||
store_location_for(:user, request.fullpath)
|
||||
end
|
||||
|
@ -292,7 +304,7 @@ module Users
|
|||
|
||||
def show_demarche_en_test_banner
|
||||
if @dossier.present? && @dossier.procedure.brouillon?
|
||||
flash.now.alert = "Ce dossier est déposé sur une démarche en test. Toute modification de la démarche par l'administrateur (ajout d'un champ, publication de la démarche...) entrainera sa suppression."
|
||||
flash.now.alert = "Ce dossier est déposé sur une démarche en test. Toute modification de la démarche par l'administrateur (ajout d'un champ, publication de la démarche...) entraînera sa suppression."
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -307,16 +319,6 @@ module Users
|
|||
[params[:page].to_i, 1].max
|
||||
end
|
||||
|
||||
def current_tab(mes_dossiers_count, dossiers_invites_count)
|
||||
if dossiers_invites_count == 0
|
||||
'mes-dossiers'
|
||||
elsif mes_dossiers_count == 0
|
||||
'dossiers-invites'
|
||||
else
|
||||
params[:current_tab].presence || 'mes-dossiers'
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: require(:dossier) when all the champs are united
|
||||
def champs_params
|
||||
params.permit(dossier: {
|
||||
|
|
|
@ -2,7 +2,15 @@ class Cron::DiscardedDossiersDeletionJob < Cron::CronJob
|
|||
self.schedule_expression = "every day at 2 am"
|
||||
|
||||
def perform(*args)
|
||||
DossierOperationLog.where(dossier: Dossier.discarded_en_construction_expired)
|
||||
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||
.destroy_all
|
||||
DossierOperationLog.where(dossier: Dossier.discarded_termine_expired)
|
||||
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||
.destroy_all
|
||||
|
||||
Dossier.discarded_brouillon_expired.destroy_all
|
||||
Dossier.discarded_en_construction_expired.destroy_all
|
||||
Dossier.discarded_termine_expired.destroy_all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -75,6 +75,20 @@ class DossierMailer < ApplicationMailer
|
|||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_instructeur_deletion_to_user(deleted_dossier, to_email)
|
||||
@subject = default_i18n_subject(libelle_demarche: deleted_dossier.procedure.libelle)
|
||||
@deleted_dossier = deleted_dossier
|
||||
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_instructeur(deleted_dossier, to_email)
|
||||
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
|
||||
@deleted_dossier = deleted_dossier
|
||||
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_deletion_to_administration(deleted_dossier, to_email)
|
||||
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
|
||||
@deleted_dossier = deleted_dossier
|
||||
|
|
|
@ -19,12 +19,15 @@ class DeletedDossier < ApplicationRecord
|
|||
|
||||
validates :dossier_id, uniqueness: true
|
||||
|
||||
scope :order_by_updated_at, -> (order = :desc) { order(created_at: order) }
|
||||
|
||||
enum reason: {
|
||||
user_request: 'user_request',
|
||||
manager_request: 'manager_request',
|
||||
user_removed: 'user_removed',
|
||||
procedure_removed: 'procedure_removed',
|
||||
expired: 'expired'
|
||||
expired: 'expired',
|
||||
instructeur_request: 'instructeur_request'
|
||||
}
|
||||
|
||||
def self.create_from_dossier(dossier, reason)
|
||||
|
|
|
@ -263,13 +263,19 @@ class Dossier < ApplicationRecord
|
|||
with_discarded
|
||||
.discarded
|
||||
.state_brouillon
|
||||
.where('hidden_at < ?', 1.month.ago)
|
||||
.where('hidden_at < ?', 1.week.ago)
|
||||
end
|
||||
scope :discarded_en_construction_expired, -> do
|
||||
with_discarded
|
||||
.discarded
|
||||
.state_en_construction
|
||||
.where('dossiers.hidden_at < ?', 1.month.ago)
|
||||
.where('dossiers.hidden_at < ?', 1.week.ago)
|
||||
end
|
||||
scope :discarded_termine_expired, -> do
|
||||
with_discarded
|
||||
.discarded
|
||||
.state_termine
|
||||
.where('dossiers.hidden_at < ?', 1.week.ago)
|
||||
end
|
||||
|
||||
scope :brouillon_near_procedure_closing_date, -> do
|
||||
|
@ -521,16 +527,24 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
def discard_and_keep_track!(author, reason)
|
||||
if keep_track_on_deletion? && en_construction?
|
||||
deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
|
||||
if keep_track_on_deletion?
|
||||
if en_construction?
|
||||
deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
|
||||
|
||||
administration_emails = followers_instructeurs.present? ? followers_instructeurs.map(&:email) : procedure.administrateurs.map(&:email)
|
||||
administration_emails.each do |email|
|
||||
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
||||
administration_emails = followers_instructeurs.present? ? followers_instructeurs.map(&:email) : procedure.administrateurs.map(&:email)
|
||||
administration_emails.each do |email|
|
||||
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
||||
end
|
||||
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
|
||||
|
||||
log_dossier_operation(author, :supprimer, self)
|
||||
elsif termine?
|
||||
deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
|
||||
|
||||
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user.email).deliver_later
|
||||
|
||||
log_dossier_operation(author, :supprimer, self)
|
||||
end
|
||||
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
|
||||
|
||||
log_dossier_operation(author, :supprimer, self)
|
||||
end
|
||||
|
||||
discard!
|
||||
|
|
|
@ -58,7 +58,7 @@ class DossierOperationLog < ApplicationRecord
|
|||
operation: operation_log.operation,
|
||||
dossier_id: operation_log.dossier_id,
|
||||
author: self.serialize_author(params[:author]),
|
||||
subject: self.serialize_subject(params[:subject]),
|
||||
subject: self.serialize_subject(params[:subject], operation_log.operation),
|
||||
automatic_operation: operation_log.automatic_operation?,
|
||||
executed_at: operation_log.executed_at.iso8601
|
||||
}.compact.to_json
|
||||
|
@ -84,9 +84,15 @@ class DossierOperationLog < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def self.serialize_subject(subject)
|
||||
def self.serialize_subject(subject, operation = nil)
|
||||
if subject.nil?
|
||||
nil
|
||||
elsif operation == operations.fetch(:supprimer)
|
||||
{
|
||||
date_de_depot: subject.en_construction_at,
|
||||
date_de_mise_en_instruction: subject.en_instruction_at,
|
||||
date_de_decision: subject.termine? ? subject.traitements.last.processed_at : nil
|
||||
}.as_json
|
||||
else
|
||||
case subject
|
||||
when Dossier
|
||||
|
|
|
@ -44,6 +44,7 @@ class User < ApplicationRecord
|
|||
has_many :invites, dependent: :destroy
|
||||
has_many :dossiers_invites, through: :invites, source: :dossier
|
||||
has_many :feedbacks, dependent: :destroy
|
||||
has_many :deleted_dossiers
|
||||
has_one :france_connect_information, dependent: :destroy
|
||||
belongs_to :instructeur, optional: true
|
||||
belongs_to :administrateur, optional: true
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
- content_for(:title, "#{@subject}")
|
||||
|
||||
%p
|
||||
Bonjour,
|
||||
|
||||
%p
|
||||
= t('.body_html', dossier_id: @deleted_dossier.dossier_id, libelle_demarche: @deleted_dossier.procedure.libelle, deleted_dossiers_link: dossiers_url(statut: 'dossiers-supprimes'))
|
||||
|
||||
= render partial: "layouts/mailers/signature"
|
|
@ -105,3 +105,11 @@
|
|||
.dropdown-description
|
||||
%h4 Repasser en instruction
|
||||
L’usager sera notifié que son dossier est réexaminé.
|
||||
- if dossier.termine?
|
||||
%li
|
||||
= link_to supprimer_dossier_instructeur_dossier_path(dossier.procedure, dossier), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier.id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do
|
||||
%span.icon.delete
|
||||
.dropdown-description
|
||||
%h4 Supprimer le dossier
|
||||
L’usager sera notifié que son dossier est supprimé.
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
%tr
|
||||
%th.notification-col
|
||||
%th.number-col N° dossier
|
||||
%th.status-col Etat
|
||||
%th.status-col Raison de suppression
|
||||
%th.status-col Date de suppression
|
||||
%tbody
|
||||
|
@ -62,8 +61,6 @@
|
|||
%span.icon.folder
|
||||
%td.number-col
|
||||
= deleted_dossier.dossier_id
|
||||
%td.status-col
|
||||
= status_badge(deleted_dossier.state)
|
||||
%td.reason-col
|
||||
= deletion_reason_badge(deleted_dossier.reason)
|
||||
%td.date-col.deleted-cell
|
||||
|
|
43
app/views/users/dossiers/_deleted_dossiers_list.html.haml
Normal file
43
app/views/users/dossiers/_deleted_dossiers_list.html.haml
Normal file
|
@ -0,0 +1,43 @@
|
|||
- if deleted_dossiers.present?
|
||||
%table.table.dossiers-table.hoverable
|
||||
%thead
|
||||
%tr
|
||||
%th.number-col Nº dossier
|
||||
%th Démarche
|
||||
%th Raison de suppression
|
||||
%th Date de suppression
|
||||
%tbody
|
||||
- deleted_dossiers.each do |dossier|
|
||||
- libelle_demarche = Procedure.find(dossier.procedure_id).libelle
|
||||
%tr{ data: { 'dossier-id': dossier.dossier_id } }
|
||||
%td.number-col
|
||||
%span.icon.folder
|
||||
= dossier.dossier_id
|
||||
%td
|
||||
= libelle_demarche
|
||||
|
||||
%td.cell-link
|
||||
= deletion_reason_badge(dossier.reason)
|
||||
%td
|
||||
= dossier.updated_at.strftime('%d/%m/%Y')
|
||||
|
||||
= paginate(deleted_dossiers)
|
||||
|
||||
- if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago
|
||||
#user-satisfaction
|
||||
%h3 Que pensez-vous de la facilité d'utilisation de ce service ?
|
||||
.icons
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:unhappy)), data: { remote: true, method: :post } do
|
||||
%span.icon.frown
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:neutral)), data: { remote: true, method: :post } do
|
||||
%span.icon.meh
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:happy)), data: { remote: true, method: :post } do
|
||||
%span.icon.smile
|
||||
|
||||
- else
|
||||
.blank-tab
|
||||
%h2.empty-text Aucun dossier.
|
||||
%p.empty-text-details
|
||||
Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche.
|
||||
%br
|
||||
Celui ci doit ressembler à #{APPLICATION_BASE_URL}/commencer/xxx.
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
- if has_delete_action
|
||||
%li.danger
|
||||
= link_to ask_deletion_dossier_path(dossier), method: :post, data: { disable: true, confirm: "En continuant, vous allez supprimer ce dossier ainsi que les informations qu’il contient. Toute suppression entraine l’annulation de la démarche en cours.\n\nConfirmer la suppression ?" } do
|
||||
= link_to ask_deletion_dossier_path(dossier), method: :post, data: { disable: true, confirm: "En continuant, vous allez supprimer ce dossier ainsi que les informations qu’il contient. Toute suppression entraîne l’annulation de la démarche en cours.\n\nConfirmer la suppression ?" } do
|
||||
%span.icon.delete
|
||||
.dropdown-description
|
||||
Supprimer le dossier
|
||||
|
|
51
app/views/users/dossiers/_dossiers_list.html.haml
Normal file
51
app/views/users/dossiers/_dossiers_list.html.haml
Normal file
|
@ -0,0 +1,51 @@
|
|||
- if dossiers.present?
|
||||
%table.table.dossiers-table.hoverable
|
||||
%thead
|
||||
%tr
|
||||
%th.number-col Nº dossier
|
||||
%th Démarche
|
||||
- if dossiers.present?
|
||||
%th Demandeur
|
||||
%th.status-col Statut
|
||||
%th.updated-at-col Mis à jour
|
||||
%th.sr-only Actions
|
||||
%tbody
|
||||
- dossiers.each do |dossier|
|
||||
%tr{ data: { 'dossier-id': dossier.id } }
|
||||
%td.number-col
|
||||
= link_to(url_for_dossier(dossier), class: 'cell-link', tabindex: -1) do
|
||||
%span.icon.folder
|
||||
= dossier.id
|
||||
%td
|
||||
= link_to(url_for_dossier(dossier), class: 'cell-link') do
|
||||
= procedure_libelle(dossier.procedure)
|
||||
- if dossiers.present?
|
||||
%td.cell-link
|
||||
= demandeur_dossier(dossier)
|
||||
%td.status-col
|
||||
= status_badge(dossier.state)
|
||||
%td.updated-at-col.cell-link
|
||||
= try_format_date(dossier.updated_at)
|
||||
%td.action-col
|
||||
= render partial: 'dossier_actions', locals: { dossier: dossier }
|
||||
|
||||
= paginate(dossiers)
|
||||
|
||||
- if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago
|
||||
#user-satisfaction
|
||||
%h3 Que pensez-vous de la facilité d'utilisation de ce service ?
|
||||
.icons
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:unhappy)), data: { remote: true, method: :post } do
|
||||
%span.icon.frown
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:neutral)), data: { remote: true, method: :post } do
|
||||
%span.icon.meh
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:happy)), data: { remote: true, method: :post } do
|
||||
%span.icon.smile
|
||||
|
||||
- else
|
||||
.blank-tab
|
||||
%h2.empty-text Aucun dossier.
|
||||
%p.empty-text-details
|
||||
Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche.
|
||||
%br
|
||||
Celui ci doit ressembler à #{APPLICATION_BASE_URL}/commencer/xxx.
|
|
@ -10,68 +10,36 @@
|
|||
.container
|
||||
- if @search_terms.present?
|
||||
%h1.page-title Résultat de la recherche pour « #{@search_terms} »
|
||||
- elsif @dossiers_invites.count == 0
|
||||
%h1.page-title Mes dossiers
|
||||
= render partial: "dossiers_list", locals: { dossiers: @dossiers }
|
||||
|
||||
- else
|
||||
%h1.page-title Dossiers
|
||||
%ul.tabs
|
||||
= tab_item('mes dossiers',
|
||||
dossiers_path(current_tab: 'mes-dossiers'),
|
||||
active: @current_tab == 'mes-dossiers')
|
||||
- if @user_dossiers.count > 0
|
||||
= tab_item(t('pluralize.mes_dossiers', count: @user_dossiers.count),
|
||||
dossiers_path(statut: 'mes-dossiers'),
|
||||
active: @statut == 'mes-dossiers',
|
||||
badge: number_with_html_delimiter(@user_dossiers.count))
|
||||
|
||||
- if @dossiers_invites.count > 0
|
||||
= tab_item(t('pluralize.dossiers_invites', count: @dossiers_invites.count),
|
||||
dossiers_path(statut: 'dossiers-invites'),
|
||||
active: @statut == 'dossiers-invites',
|
||||
badge: number_with_html_delimiter(@dossiers_invites.count))
|
||||
|
||||
- if @dossiers_supprimes.count > 0
|
||||
= tab_item(t('pluralize.dossiers_supprimes', count: @dossiers_supprimes.count),
|
||||
dossiers_path(statut: 'dossiers-supprimes'),
|
||||
active: @statut == 'dossiers-supprimes',
|
||||
badge: number_with_html_delimiter(@dossiers_supprimes.count))
|
||||
|
||||
= tab_item('dossiers invités',
|
||||
dossiers_path(current_tab: 'dossiers-invites'),
|
||||
active: @current_tab == 'dossiers-invites')
|
||||
|
||||
.container
|
||||
- if @dossiers.present?
|
||||
%table.table.dossiers-table.hoverable
|
||||
%thead
|
||||
%tr
|
||||
%th.number-col Nº dossier
|
||||
%th Démarche
|
||||
- if @dossiers.count > 1
|
||||
%th Demandeur
|
||||
%th.status-col Statut
|
||||
%th.updated-at-col Mis à jour
|
||||
%th.sr-only Actions
|
||||
%tbody
|
||||
- @dossiers.each do |dossier|
|
||||
%tr{ data: { 'dossier-id': dossier.id } }
|
||||
%td.number-col
|
||||
= link_to(url_for_dossier(dossier), class: 'cell-link', tabindex: -1) do
|
||||
%span.icon.folder
|
||||
= dossier.id
|
||||
%td
|
||||
= link_to(url_for_dossier(dossier), class: 'cell-link') do
|
||||
= procedure_libelle(dossier.procedure)
|
||||
- if @dossiers.count > 1
|
||||
%td.cell-link
|
||||
= demandeur_dossier(dossier)
|
||||
%td.status-col
|
||||
= status_badge(dossier.state)
|
||||
%td.updated-at-col.cell-link
|
||||
= try_format_date(dossier.updated_at)
|
||||
%td.action-col
|
||||
= render partial: 'dossier_actions', locals: { dossier: dossier }
|
||||
= paginate(@dossiers)
|
||||
- if @statut == "mes-dossiers"
|
||||
= render partial: "dossiers_list", locals: { dossiers: @user_dossiers }
|
||||
|
||||
- if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago
|
||||
#user-satisfaction
|
||||
%h3 Que pensez-vous de la facilité d'utilisation de ce service ?
|
||||
.icons
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:unhappy)), data: { remote: true, method: :post } do
|
||||
%span.icon.frown
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:neutral)), data: { remote: true, method: :post } do
|
||||
%span.icon.meh
|
||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:happy)), data: { remote: true, method: :post } do
|
||||
%span.icon.smile
|
||||
- if @statut == "dossiers-invites"
|
||||
= render partial: "dossiers_list", locals: { dossiers: @dossiers_invites }
|
||||
|
||||
- else
|
||||
.blank-tab
|
||||
%h2.empty-text Aucun dossier.
|
||||
%p.empty-text-details
|
||||
Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche.
|
||||
%br
|
||||
Celui ci doit ressembler à #{APPLICATION_BASE_URL}/commencer/xxx.
|
||||
- if @statut == "dossiers-supprimes"
|
||||
= render partial: "deleted_dossiers_list", locals: { deleted_dossiers: @dossiers_supprimes }
|
||||
|
|
|
@ -169,6 +169,18 @@ fr:
|
|||
zero: archivé
|
||||
one: archivé
|
||||
other: archivés
|
||||
mes_dossiers:
|
||||
zero: mon dossier
|
||||
one: mon dossier
|
||||
other: mes dossiers
|
||||
dossiers_invites:
|
||||
zero: dossier invité
|
||||
one: dossier invité
|
||||
other: dossiers invités
|
||||
dossiers_supprimes:
|
||||
zero: dossier supprimé
|
||||
one: dossier supprimé
|
||||
other: dossiers supprimés
|
||||
dossier_trouve:
|
||||
zero: 0 dossier trouvé
|
||||
one: 1 dossier trouvé
|
||||
|
|
|
@ -3,9 +3,10 @@ fr:
|
|||
attributes:
|
||||
deleted_dossier:
|
||||
reason:
|
||||
user_request: Demande d’usager
|
||||
user_request: Demande de l’usager
|
||||
manager_request: Demande d’administration
|
||||
user_removed: Suppression d’un compte usager
|
||||
procedure_removed: Suppression d’une démarche
|
||||
expired: Expiration
|
||||
unknown: Inconnue
|
||||
instructeur_request: Suppression par l’instructeur
|
||||
|
|
|
@ -3,3 +3,9 @@ fr:
|
|||
notify_deletion_to_user:
|
||||
subject: Votre dossier nº %{dossier_id} a bien été supprimé
|
||||
body: Votre dossier n° %{dossier_id} (%{procedure}) a bien été supprimé. Une trace de ce traitement sera conservée pour l’administration.
|
||||
notify_instructeur_deletion_to_user:
|
||||
subject: Votre dossier sur la démarche « %{libelle_demarche} » est supprimé
|
||||
body_html: |
|
||||
Afin de limiter la conservation de vos données personnelles, votre dossier n° %{dossier_id} concernant la démarche <b>« %{libelle_demarche} »</b> est <b>supprimé</b>.<br><br>
|
||||
Cette suppression ne modifie pas le statut final (accepté, refusé ou sans suite) de votre dossier.<br><br>
|
||||
Une trace de ce dossier est visible dans votre interface : <a href='%{deleted_dossiers_link}'>%{deleted_dossiers_link}</a>.
|
||||
|
|
|
@ -346,6 +346,7 @@ Rails.application.routes.draw do
|
|||
patch 'unfollow'
|
||||
patch 'archive'
|
||||
patch 'unarchive'
|
||||
patch 'supprimer-dossier' => 'dossiers#delete_dossier'
|
||||
patch 'annotations' => 'dossiers#update_annotations'
|
||||
post 'commentaire' => 'dossiers#create_commentaire'
|
||||
post 'passer-en-instruction' => 'dossiers#passer_en_instruction'
|
||||
|
|
|
@ -715,4 +715,69 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#delete_dossier" do
|
||||
subject do
|
||||
patch :delete_dossier, params: {
|
||||
procedure_id: procedure.id,
|
||||
dossier_id: dossier.id
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
dossier.passer_en_instruction(instructeur)
|
||||
end
|
||||
|
||||
context 'just before delete the dossier, the operation must be equal to 2' do
|
||||
before do
|
||||
dossier.accepter!(instructeur, 'le dossier est correct')
|
||||
end
|
||||
|
||||
it 'has 2 operations logs before deletion' do
|
||||
expect(DossierOperationLog.where(dossier_id: dossier.id).count).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instructeur want to delete a dossier with a decision' do
|
||||
before do
|
||||
dossier.accepter!(instructeur, "le dossier est correct")
|
||||
allow(DossierMailer).to receive(:notify_instructeur_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
subject
|
||||
end
|
||||
|
||||
it 'deletes previous logs and add a suppression log' do
|
||||
expect(DossierOperationLog.where(dossier_id: dossier.id).count).to eq(3)
|
||||
expect(DossierOperationLog.where(dossier_id: dossier.id).last.operation).to eq('supprimer')
|
||||
end
|
||||
|
||||
it 'send an email to the user' do
|
||||
expect(DossierMailer).to have_received(:notify_instructeur_deletion_to_user).with(DeletedDossier.where(dossier_id: dossier.id).first, dossier.user.email)
|
||||
end
|
||||
|
||||
it 'add a record into deleted_dossiers table' do
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).count).to eq(1)
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).first.revision_id).to eq(dossier.revision_id)
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).first.user_id).to eq(dossier.user_id)
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).first.groupe_instructeur_id).to eq(dossier.groupe_instructeur_id)
|
||||
end
|
||||
|
||||
it 'discard the dossier' do
|
||||
expect(dossier.reload.hidden_at).not_to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instructeur want to delete a dossier without a decision' do
|
||||
before do
|
||||
subject
|
||||
end
|
||||
|
||||
it 'does not delete the dossier' do
|
||||
expect { dossier.reload }.not_to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
it 'does not add a record into deleted_dossiers table' do
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).count).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -743,16 +743,15 @@ describe Users::DossiersController, type: :controller do
|
|||
context 'when the user does not have any dossiers' do
|
||||
before { get(:index) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
||||
end
|
||||
|
||||
context 'when the user only have its own dossiers' do
|
||||
let!(:own_dossier) { create(:dossier, user: user) }
|
||||
|
||||
before { get(:index) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||||
it { expect(assigns(:dossiers)).to match([own_dossier]) }
|
||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
||||
it { expect(assigns(:user_dossiers)).to match([own_dossier]) }
|
||||
end
|
||||
|
||||
context 'when the user only have some dossiers invites' do
|
||||
|
@ -760,30 +759,30 @@ describe Users::DossiersController, type: :controller do
|
|||
|
||||
before { get(:index) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('dossiers-invites') }
|
||||
it { expect(assigns(:dossiers)).to match([invite.dossier]) }
|
||||
it { expect(assigns(:statut)).to eq('dossiers-invites') }
|
||||
it { expect(assigns(:dossiers_invites)).to match([invite.dossier]) }
|
||||
end
|
||||
|
||||
context 'when the user has both' do
|
||||
let!(:own_dossier) { create(:dossier, user: user) }
|
||||
let!(:invite) { create(:invite, dossier: create(:dossier), user: user) }
|
||||
|
||||
context 'and there is no current_tab param' do
|
||||
context 'and there is no statut param' do
|
||||
before { get(:index) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
||||
end
|
||||
|
||||
context 'and there is "dossiers-invites" param' do
|
||||
before { get(:index, params: { current_tab: 'dossiers-invites' }) }
|
||||
before { get(:index, params: { statut: 'dossiers-invites' }) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('dossiers-invites') }
|
||||
it { expect(assigns(:statut)).to eq('dossiers-invites') }
|
||||
end
|
||||
|
||||
context 'and there is "mes-dossiers" param' do
|
||||
before { get(:index, params: { current_tab: 'mes-dossiers' }) }
|
||||
before { get(:index, params: { statut: 'mes-dossiers' }) }
|
||||
|
||||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -111,6 +111,9 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :brouillon do
|
||||
end
|
||||
|
||||
trait :en_construction do
|
||||
after(:create) do |dossier, _evaluator|
|
||||
dossier.state = Dossier.states.fetch(:en_construction)
|
||||
|
|
68
spec/jobs/cron/discarded_dossiers_deletion_job_spec.rb
Normal file
68
spec/jobs/cron/discarded_dossiers_deletion_job_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
|
||||
describe '#perform' do
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:dossier) { create(:dossier, state, hidden_at: hidden_at) }
|
||||
|
||||
before do
|
||||
# hack to add passer_en_instruction and supprimer to dossier.dossier_operation_logs
|
||||
dossier.send(:log_dossier_operation, instructeur, :passer_en_instruction, dossier)
|
||||
dossier.send(:log_dossier_operation, instructeur, :supprimer, dossier)
|
||||
|
||||
Cron::DiscardedDossiersDeletionJob.perform_now
|
||||
end
|
||||
|
||||
def operations_left
|
||||
DossierOperationLog.where(dossier_id: dossier.id).pluck(:operation)
|
||||
end
|
||||
|
||||
RSpec.shared_examples "does not delete" do
|
||||
it 'does not delete it' do
|
||||
expect { dossier.reload }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'does not delete its operations logs' do
|
||||
expect(operations_left).to match_array(["passer_en_instruction", "supprimer"])
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples "does delete" do
|
||||
it 'does delete it' do
|
||||
expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'deletes its operations logs except supprimer' do
|
||||
expect(operations_left).to eq(["supprimer"])
|
||||
end
|
||||
end
|
||||
|
||||
[:brouillon, :en_construction, :en_instruction, :accepte, :refuse, :sans_suite].each do |state|
|
||||
context "with a dossier #{state}" do
|
||||
let(:state) { state }
|
||||
|
||||
context 'not hidden' do
|
||||
let(:hidden_at) { nil }
|
||||
|
||||
include_examples "does not delete"
|
||||
end
|
||||
|
||||
context 'hidden not so long ago' do
|
||||
let(:hidden_at) { 1.week.ago + 1.hour }
|
||||
|
||||
include_examples "does not delete"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[:en_construction, :accepte, :refuse, :sans_suite].each do |state|
|
||||
context "with a dossier #{state}" do
|
||||
let(:state) { state }
|
||||
|
||||
context 'hidden long ago' do
|
||||
let(:hidden_at) { 1.week.ago - 1.hour }
|
||||
|
||||
include_examples "does delete"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,6 +49,10 @@ class DossierMailerPreview < ActionMailer::Preview
|
|||
DossierMailer.notify_deletion_to_user(deleted_dossier, usager_email)
|
||||
end
|
||||
|
||||
def notify_instructeur_deletion_to_user
|
||||
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, usager_email)
|
||||
end
|
||||
|
||||
def notify_deletion_to_administration
|
||||
DossierMailer.notify_deletion_to_administration(deleted_dossier, administration_email)
|
||||
end
|
||||
|
|
|
@ -1268,8 +1268,8 @@ describe Dossier do
|
|||
end
|
||||
end
|
||||
|
||||
it { expect(Dossier.discarded_brouillon_expired.count).to eq(2) }
|
||||
it { expect(Dossier.discarded_en_construction_expired.count).to eq(2) }
|
||||
it { expect(Dossier.discarded_brouillon_expired.count).to eq(3) }
|
||||
it { expect(Dossier.discarded_en_construction_expired.count).to eq(3) }
|
||||
end
|
||||
|
||||
describe "discarded procedure dossier should be able to access it's procedure" do
|
||||
|
|
|
@ -70,7 +70,7 @@ describe 'instructeurs/dossiers/state_button.html.haml', type: :view do
|
|||
|
||||
it 'renders a dropdown' do
|
||||
expect(rendered).to have_dropdown_title(dossier_display_state(dossier))
|
||||
expect(rendered).to have_dropdown_items(count: 1)
|
||||
expect(rendered).to have_dropdown_items(count: 2)
|
||||
expect(rendered).to have_dropdown_item('Repasser en instruction', href: repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier))
|
||||
end
|
||||
|
||||
|
|
|
@ -4,15 +4,15 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
|||
let(:dossier_en_construction) { create(:dossier, state: Dossier.states.fetch(:en_construction), user: user) }
|
||||
let(:user_dossiers) { [dossier_brouillon, dossier_en_construction] }
|
||||
let(:dossiers_invites) { [] }
|
||||
let(:current_tab) { 'mes-dossiers' }
|
||||
let(:statut) { 'mes-dossiers' }
|
||||
|
||||
before do
|
||||
allow(view).to receive(:new_demarche_url).and_return('#')
|
||||
allow(controller).to receive(:current_user) { user }
|
||||
assign(:user_dossiers, Kaminari.paginate_array(user_dossiers).page(1))
|
||||
assign(:dossiers_invites, Kaminari.paginate_array(dossiers_invites).page(1))
|
||||
assign(:dossiers, Kaminari.paginate_array(user_dossiers).page(1))
|
||||
assign(:current_tab, current_tab)
|
||||
assign(:dossiers_supprimes, Kaminari.paginate_array(user_dossiers).page(1))
|
||||
assign(:statut, statut)
|
||||
render
|
||||
end
|
||||
|
||||
|
@ -48,11 +48,11 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
|||
let(:dossiers_invites) { [] }
|
||||
|
||||
it 'affiche un titre adapté' do
|
||||
expect(rendered).to have_selector('h1', text: 'Mes dossiers')
|
||||
expect(rendered).to have_selector('h1', text: 'Dossiers')
|
||||
end
|
||||
|
||||
it 'n’affiche pas la barre d’onglets' do
|
||||
expect(rendered).not_to have_selector('ul.tabs')
|
||||
it 'n’affiche la barre d’onglets' do
|
||||
expect(rendered).to have_selector('ul.tabs')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,7 +65,7 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
|||
|
||||
it 'affiche la barre d’onglets' do
|
||||
expect(rendered).to have_selector('ul.tabs')
|
||||
expect(rendered).to have_selector('ul.tabs li', count: 2)
|
||||
expect(rendered).to have_selector('ul.tabs li', count: 3)
|
||||
expect(rendered).to have_selector('ul.tabs li.active', count: 1)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue