Merge pull request #9930 from demarches-simplifiees/add-external-link-to-procedure
ETQ admin lorsque je clos une démarche je peux alerter les usagers et je crée une page de fermeture si la démarche n'est pas redirigée dans DS
This commit is contained in:
commit
ee92668611
40 changed files with 721 additions and 47 deletions
|
@ -1,9 +1,13 @@
|
|||
class Dsfr::ToggleComponent < ApplicationComponent
|
||||
def initialize(form:, target:, title:, hint:, disabled:)
|
||||
def initialize(form:, target:, title:, disabled: nil, hint: nil, toggle_labels: { checked: 'Activé', unchecked: 'Désactivé' }, opt: nil)
|
||||
@form = form
|
||||
@target = target
|
||||
@title = title
|
||||
@hint = hint
|
||||
@disabled = disabled
|
||||
@toggle_labels = toggle_labels
|
||||
@opt = opt
|
||||
end
|
||||
|
||||
attr_reader :toggle_labels
|
||||
end
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
.fr-toggle.fr-toggle--border-bottom.fr-toggle--label-left
|
||||
= @form.check_box @target, class: 'fr-toggle__input', disabled: @disabled
|
||||
.fr-toggle.fr-toggle--label-left
|
||||
= @form.check_box @target, class: 'fr-toggle__input', disabled: @disabled,
|
||||
data: @opt
|
||||
= @form.label @target,
|
||||
@title,
|
||||
class: 'fr-toggle__label',
|
||||
data: { 'fr-checked-label': 'Activé', 'fr-unchecked-label': 'Désactivé' }
|
||||
%p.fr-hint-text= @hint
|
||||
data: { 'fr-checked-label': toggle_labels[:checked], 'fr-unchecked-label': toggle_labels[:unchecked] },
|
||||
class: 'fr-toggle__label'
|
||||
- if @hint
|
||||
%p.fr-hint-text= @hint
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
title: 'Autogestion des instructeurs',
|
||||
hint: "L’autogestion des instructeurs permet aux instructeurs de gérer eux-mêmes la liste des instructeurs de la démarche.#{ 'Nous recommandons de laisser l’autogestion des instructeurs activée.' if @procedure.routing_enabled? }",
|
||||
disabled: false)
|
||||
|
||||
%hr
|
||||
%p.fr-mt-2w Routage
|
||||
%p.fr-mt-2w= t('.routing_configuration_notice_1')
|
||||
%p.fr-icon-info-line.fr-hint-text{ aria: { hidden: true } }
|
||||
|
|
|
@ -194,21 +194,56 @@ module Administrateurs
|
|||
def archive
|
||||
procedure = current_administrateur.procedures.find(params[:procedure_id])
|
||||
|
||||
if params[:new_procedure].present?
|
||||
new_procedure = current_administrateur.procedures.find(params[:new_procedure])
|
||||
procedure.update!(replaced_by_procedure_id: new_procedure.id)
|
||||
if procedure.update(closing_params)
|
||||
procedure.close!
|
||||
if (procedure.dossiers.not_archived.state_brouillon.present? || procedure.dossiers.not_archived.state_en_construction_ou_instruction.present?)
|
||||
redirect_to admin_procedure_closing_notification_path
|
||||
else
|
||||
flash.notice = "Démarche close"
|
||||
redirect_to admin_procedure_path(id: procedure.id)
|
||||
end
|
||||
else
|
||||
flash.alert = procedure.errors.full_messages
|
||||
redirect_to admin_procedure_close_path
|
||||
end
|
||||
|
||||
procedure.close!
|
||||
|
||||
flash.notice = "Démarche close"
|
||||
redirect_to admin_procedures_path
|
||||
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash.alert = 'Démarche inexistante'
|
||||
redirect_to admin_procedures_path
|
||||
end
|
||||
|
||||
def closing_notification
|
||||
@procedure = current_administrateur.procedures.find(params[:procedure_id])
|
||||
@users_brouillon_count = @procedure.dossiers.not_archived.state_brouillon.count('distinct user_id')
|
||||
@users_en_cours_count = @procedure.dossiers.not_archived.state_en_construction_ou_instruction.count('distinct user_id')
|
||||
end
|
||||
|
||||
def notify_after_closing
|
||||
@procedure = current_administrateur.procedures.find(params[:procedure_id])
|
||||
@procedure.update!(notification_closing_params)
|
||||
|
||||
if (@procedure.closing_notification_brouillon? && params[:email_content_brouillon].blank?) || (@procedure.closing_notification_en_cours? && params[:email_content_en_cours].blank?)
|
||||
flash.alert = "Veuillez renseigner le contenu de l’email afin d’informer les usagers"
|
||||
redirect_to admin_procedure_closing_notification_path and return
|
||||
end
|
||||
|
||||
if @procedure.closing_notification_brouillon?
|
||||
user_ids = @procedure.dossiers.not_archived.state_brouillon.pluck(:user_id).uniq
|
||||
content = params[:email_content_brouillon]
|
||||
SendClosingNotificationJob.perform_later(user_ids, content, @procedure)
|
||||
flash.notice = "Les emails sont en cours d'envoi"
|
||||
end
|
||||
|
||||
if @procedure.closing_notification_en_cours?
|
||||
user_ids = @procedure.dossiers.not_archived.state_en_construction_ou_instruction.pluck(:user_id).uniq
|
||||
content = params[:email_content_en_cours]
|
||||
SendClosingNotificationJob.perform_later(user_ids, content, @procedure)
|
||||
flash.notice = "Les emails sont en cours d’envoi"
|
||||
end
|
||||
|
||||
redirect_to admin_procedures_path
|
||||
end
|
||||
|
||||
def destroy
|
||||
procedure = current_administrateur.procedures.find(params[:id])
|
||||
|
||||
|
@ -301,6 +336,10 @@ module Administrateurs
|
|||
.update!(replaced_by_procedure: @procedure)
|
||||
end
|
||||
|
||||
# TO DO after data backfill add this condition before reset :
|
||||
# if @procedure.closing_reason.present?
|
||||
@procedure.reset_closing_params
|
||||
|
||||
redirect_to admin_procedure_confirmation_path(@procedure)
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
flash.alert = @procedure.errors.full_messages
|
||||
|
@ -327,6 +366,7 @@ module Administrateurs
|
|||
|
||||
def close
|
||||
@published_procedures = current_administrateur.procedures.publiees.to_h { |p| ["#{p.libelle} (#{p.id})", p.id] }
|
||||
@closing_reason_options = Procedure.closing_reasons.values.map { |reason| [I18n.t("activerecord.attributes.procedure.closing_reasons.#{reason}"), reason] }
|
||||
end
|
||||
|
||||
def confirmation
|
||||
|
@ -494,6 +534,22 @@ module Administrateurs
|
|||
params.permit(:path, :lien_site_web)
|
||||
end
|
||||
|
||||
def closing_params
|
||||
closing_params = params.require(:procedure).permit(:closing_details, :closing_reason, :replaced_by_procedure_id)
|
||||
|
||||
replaced_by_procedure_id = closing_params[:replaced_by_procedure_id]
|
||||
if replaced_by_procedure_id.present?
|
||||
if current_administrateur.procedures.find_by(id: replaced_by_procedure_id).blank?
|
||||
closing_params.delete(:replaced_by_procedure_id)
|
||||
end
|
||||
end
|
||||
closing_params
|
||||
end
|
||||
|
||||
def notification_closing_params
|
||||
params.require(:procedure).permit(:closing_notification_brouillon, :closing_notification_en_cours)
|
||||
end
|
||||
|
||||
def allow_decision_access_params
|
||||
params.require(:experts_procedure).permit(:allow_decision_access)
|
||||
end
|
||||
|
|
|
@ -78,6 +78,11 @@ module Users
|
|||
current_user ? :user : :guest
|
||||
end
|
||||
|
||||
def closing_details
|
||||
@procedure = Procedure.find_by(path: params[:path])
|
||||
render 'closing_details', layout: 'closing_details'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def extra_query_params
|
||||
|
@ -136,9 +141,8 @@ module Users
|
|||
redirect_to commencer_path(procedure.replaced_by_procedure.path, **extra_query_params)
|
||||
return
|
||||
elsif procedure&.close?
|
||||
flash.alert = procedure.service.presence ?
|
||||
t('errors.messages.procedure_archived.with_service_and_phone_email', service_name: procedure.service.nom, service_phone_number: procedure.service.telephone, service_email: procedure.service.email) :
|
||||
t('errors.messages.procedure_archived.with_organisation_only', organisation_name: procedure.organisation)
|
||||
redirect_to closing_details_path(procedure.path)
|
||||
return
|
||||
else
|
||||
flash.alert = t('errors.messages.procedure_not_found')
|
||||
end
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import { ApplicationController } from './application_controller';
|
||||
import { hide, show } from '@utils';
|
||||
|
||||
export class ClosingNotificationController extends ApplicationController {
|
||||
static targets = [
|
||||
'brouillonToggle',
|
||||
'emailContentBrouillon',
|
||||
'enCoursToggle',
|
||||
'emailContentEnCours',
|
||||
'submit'
|
||||
];
|
||||
|
||||
declare readonly brouillonToggleTarget: HTMLInputElement;
|
||||
declare readonly hasBrouillonToggleTarget: boolean;
|
||||
declare readonly enCoursToggleTarget: HTMLInputElement;
|
||||
declare readonly hasEnCoursToggleTarget: boolean;
|
||||
declare readonly emailContentBrouillonTarget: HTMLElement;
|
||||
declare readonly emailContentEnCoursTarget: HTMLElement;
|
||||
declare readonly submitTarget: HTMLButtonElement;
|
||||
|
||||
connect() {
|
||||
this.displayBrouillonInput();
|
||||
this.displayEnCoursInput();
|
||||
this.on('change', () => this.onChange());
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.displayBrouillonInput();
|
||||
this.displayEnCoursInput();
|
||||
}
|
||||
|
||||
displayBrouillonInput() {
|
||||
if (this.hasBrouillonToggleTarget) {
|
||||
const brouillonToggleElement = this
|
||||
.brouillonToggleTarget as HTMLInputElement;
|
||||
|
||||
const emailContentBrouillonElement = this
|
||||
.emailContentBrouillonTarget as HTMLElement;
|
||||
|
||||
if (emailContentBrouillonElement) {
|
||||
if (brouillonToggleElement.checked) {
|
||||
show(emailContentBrouillonElement);
|
||||
} else {
|
||||
hide(emailContentBrouillonElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
displayEnCoursInput() {
|
||||
if (this.hasEnCoursToggleTarget) {
|
||||
const enCoursToggleElement = this.enCoursToggleTarget as HTMLInputElement;
|
||||
|
||||
const emailContentEnCoursElement = this
|
||||
.emailContentEnCoursTarget as HTMLElement;
|
||||
|
||||
if (emailContentEnCoursElement) {
|
||||
if (enCoursToggleElement.checked) {
|
||||
show(this.emailContentEnCoursTarget);
|
||||
} else {
|
||||
hide(this.emailContentEnCoursTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enableSubmitOnClick() {
|
||||
if (
|
||||
this.element.querySelectorAll('input[type="checkbox"]:checked').length > 0
|
||||
) {
|
||||
this.submitTarget.disabled = false;
|
||||
} else {
|
||||
this.submitTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
44
app/javascript/controllers/closing_reason_controller.ts
Normal file
44
app/javascript/controllers/closing_reason_controller.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { ApplicationController } from './application_controller';
|
||||
import { hide, show } from '@utils';
|
||||
|
||||
export class ClosingReasonController extends ApplicationController {
|
||||
static targets = ['closingReason', 'replacedByProcedureId', 'closingDetails'];
|
||||
|
||||
declare closingReasonTarget: HTMLSelectElement;
|
||||
declare replacedByProcedureIdTarget: HTMLInputElement;
|
||||
declare closingDetailsTarget: HTMLInputElement;
|
||||
|
||||
connect() {
|
||||
this.displayInput();
|
||||
this.on('change', () => this.onChange());
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.displayInput();
|
||||
}
|
||||
|
||||
displayInput() {
|
||||
const closingReasonSelect = this.closingReasonTarget as HTMLSelectElement;
|
||||
|
||||
Array.from(closingReasonSelect.options).forEach((option) => {
|
||||
if (option.selected && option.value == 'internal_procedure') {
|
||||
show(this.replacedByProcedureIdTarget);
|
||||
hide(this.closingDetailsTarget);
|
||||
this.emptyValue(this.closingDetailsTarget.querySelector('input'));
|
||||
} else if (option.selected && option.value == 'other') {
|
||||
hide(this.replacedByProcedureIdTarget);
|
||||
this.emptyValue(
|
||||
this.replacedByProcedureIdTarget.querySelector('select')
|
||||
);
|
||||
show(this.closingDetailsTarget);
|
||||
this.emptyValue(this.closingDetailsTarget.querySelector('input'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
emptyValue(field: HTMLInputElement | HTMLSelectElement | null) {
|
||||
if (field) {
|
||||
field.value = '';
|
||||
}
|
||||
}
|
||||
}
|
7
app/jobs/send_closing_notification_job.rb
Normal file
7
app/jobs/send_closing_notification_job.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class SendClosingNotificationJob < ApplicationJob
|
||||
def perform(user_ids, content, procedure)
|
||||
User.where(id: user_ids).find_each do |user|
|
||||
Expired::MailRateLimiter.new().send_with_delay(UserMailer.notify_after_closing(user, content, @procedure))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -74,6 +74,15 @@ class UserMailer < ApplicationMailer
|
|||
mail(to: user.email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_after_closing(user, content, procedure = nil)
|
||||
@user = user
|
||||
@subject = "Clôture d'une démarche sur Démarches simplifiées"
|
||||
@procedure = procedure
|
||||
@content = content
|
||||
|
||||
mail(to: user.email, subject: @subject, content: @content, procedure: @procedure)
|
||||
end
|
||||
|
||||
def self.critical_email?(action_name)
|
||||
[
|
||||
'france_connect_merge_confirmation',
|
||||
|
|
|
@ -223,6 +223,11 @@ class Procedure < ApplicationRecord
|
|||
accepte: 'accepte'
|
||||
}
|
||||
|
||||
enum closing_reason: {
|
||||
internal_procedure: 'internal_procedure',
|
||||
other: 'other'
|
||||
}
|
||||
|
||||
scope :for_api_v2, -> {
|
||||
includes(:draft_revision, :published_revision, administrateurs: :user)
|
||||
}
|
||||
|
@ -260,6 +265,9 @@ class Procedure < ApplicationRecord
|
|||
|
||||
validate :check_juridique, on: [:create, :publication]
|
||||
|
||||
# TO DO add validation after data backfill
|
||||
# validates :replaced_by_id, presence: true, if: -> { closing_reason == self.closing_reasons.fetch(:internal_procedure) }
|
||||
|
||||
validates :path, presence: true, format: { with: /\A[a-z0-9_\-]{3,200}\z/ }, uniqueness: { scope: [:path, :closed_at, :hidden_at, :unpublished_at], case_sensitive: false }
|
||||
validates :duree_conservation_dossiers_dans_ds, allow_nil: false,
|
||||
numericality: {
|
||||
|
@ -1002,6 +1010,10 @@ class Procedure < ApplicationRecord
|
|||
.first
|
||||
end
|
||||
|
||||
def reset_closing_params
|
||||
update!(closing_reason: nil, closing_details: nil, replaced_by_procedure_id: nil, closing_notification_brouillon: false, closing_notification_en_cours: false)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pieces_jointes_list
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Maintenance
|
||||
class BackfillClosingReasonInClosedProceduresTask < MaintenanceTasks::Task
|
||||
def collection
|
||||
Procedure
|
||||
.with_discarded
|
||||
.where(aasm_state: :close)
|
||||
end
|
||||
|
||||
def process(procedure)
|
||||
if procedure.replaced_by_procedure_id.present?
|
||||
procedure.update!(closing_reason: Procedure.closing_reasons.fetch(:internal_procedure))
|
||||
else
|
||||
procedure.update!(closing_reason: Procedure.closing_reasons.fetch(:other))
|
||||
end
|
||||
end
|
||||
|
||||
def count
|
||||
collection.count
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,15 +8,21 @@
|
|||
.fr-col-12.fr-col-offset-md-2.fr-col-md-8
|
||||
%h1= t('administrateurs.procedures.close.page_title')
|
||||
|
||||
%p= t('administrateurs.procedures.close.replacement_procedure_title')
|
||||
= render Dsfr::CalloutComponent.new(title: t("administrateurs.procedures.close.replacement_procedure_callout_title"), icon: "fr-fi-information-line") do |c|
|
||||
- c.with_body do
|
||||
= t('administrateurs.procedures.close.replacement_procedure_callout_content')
|
||||
|
||||
= form_tag admin_procedure_archive_path(@procedure), method: :put do
|
||||
= form_for @procedure, url: admin_procedure_archive_path(@procedure), method: :put, html: { "data-controller" => "closing-reason" } do |f|
|
||||
.fr-select-group
|
||||
= f.label :closing_reason, class: 'fr-label'
|
||||
= f.select :closing_reason, options_for_select(@closing_reason_options), {}, { class: 'fr-select', "data-closing-reason-target" => "closingReason" }
|
||||
- if @published_procedures.present?
|
||||
.fr-select-group
|
||||
= label_tag :new_procedure, class: 'fr-label' do
|
||||
= t('activerecord.attributes.procedure.new_procedure')
|
||||
= t('utils.no_mandatory')
|
||||
|
||||
= select_tag :new_procedure, options_for_select(@published_procedures), include_blank: true, class: 'fr-select'
|
||||
.fr-select-group#js_replaced_by_procedure_id{ "data-closing-reason-target" => "replacedByProcedureId" }
|
||||
= f.label :replaced_by_procedure_id, class: 'fr-label'
|
||||
= f.select :replaced_by_procedure_id, options_for_select(@published_procedures), { include_blank: "Sélectionnez la nouvelle démarche" }, { class: 'fr-select' }
|
||||
|
||||
.fr-input-group#js_closing_details{ "data-closing-reason-target" => "closingDetails" }
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :closing_details, input_type: :text_area, opts: { rows: '10', placeholder: t('activerecord.attributes.procedure.hints.closing_details_placeholder')}, required: false)
|
||||
|
||||
= submit_tag t('administrateurs.procedures.close.actions.close_procedure'), { class: "fr-btn", id: 'publish', data: { confirm: "Voulez-vous vraiment clore la démarche ? \nLes dossiers en cours pourront être instruits, mais aucun nouveau dossier ne pourra plus être déposé.", disable_with: "Archivage..."} }
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
= render partial: 'administrateurs/breadcrumbs',
|
||||
locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)],
|
||||
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],[t('administrateurs.procedures.close.page_title')]],
|
||||
metadatas: true }
|
||||
|
||||
.fr-container
|
||||
.fr-grid-row
|
||||
.fr-col-12.fr-col-offset-md-2.fr-col-md-8
|
||||
%h1= t('administrateurs.procedures.closing_notification.page_title')
|
||||
- if @procedure.closing_reason == Procedure.closing_reasons.fetch(:other)
|
||||
%h2.fr-h5= I18n.t('administrateurs.procedures.closing_notification.page_subtitle', closing_path: closing_details_path(@procedure.path)).html_safe
|
||||
- else
|
||||
%h2.fr-h5= I18n.t('administrateurs.procedures.closing_notification.page_subtitle_with_redirection', redirection_path: commencer_path(@procedure.replaced_by_procedure.path)).html_safe
|
||||
|
||||
= render Dsfr::AlertComponent.new(state: :info, size: :sm, extra_class_names: 'fr-mb-2w') do |c|
|
||||
- c.with_body do
|
||||
%p
|
||||
= t('administrateurs.procedures.closing_notification.callout_content')
|
||||
|
||||
= form_for @procedure,
|
||||
url: admin_procedure_notify_after_closing_path(@procedure),
|
||||
method: :post,
|
||||
html: { "data-controller" => "closing-notification" } do |f|
|
||||
|
||||
%div{ data: { 'action': "click->closing-notification#enableSubmitOnClick" } }
|
||||
- if @users_brouillon_count != 0
|
||||
= render Dsfr::ToggleComponent.new(form: f,
|
||||
target: :closing_notification_brouillon,
|
||||
title: t("administrateurs.procedures.closing_notification.email_toggle_brouillon", count: @users_brouillon_count),
|
||||
toggle_labels: {checked: 'Oui', unchecked: 'Non'},
|
||||
opt: {"closing-notification-target" => "brouillonToggle"})
|
||||
|
||||
.fr-input-group{ "data-closing-notification-target" => "emailContentBrouillon" }
|
||||
= label_tag :email_content_brouillon, t("administrateurs.procedures.closing_notification.email_content_brouillon"), class: "fr-label"
|
||||
= text_area_tag :email_content_brouillon, '', class: "fr-input"
|
||||
|
||||
- if @users_en_cours_count != 0
|
||||
= render Dsfr::ToggleComponent.new(form: f,
|
||||
target: :closing_notification_en_cours,
|
||||
title: t("administrateurs.procedures.closing_notification.email_toggle_en_cours", count: @users_en_cours_count),
|
||||
toggle_labels: {checked: 'Oui', unchecked: 'Non'},
|
||||
opt: {"closing-notification-target" => "enCoursToggle"})
|
||||
|
||||
.fr-input-group{ "data-closing-notification-target" => "emailContentEnCours" }
|
||||
= label_tag :email_content_en_cours, t("administrateurs.procedures.closing_notification.email_content_en_cours"), class: "fr-label"
|
||||
= text_area_tag :email_content_en_cours, '', class: "fr-input"
|
||||
|
||||
%ul.fr-btns-group.fr-btns-group--inline-md
|
||||
%li
|
||||
= submit_tag t('administrateurs.procedures.close.actions.notify_after_closing'), { class: "fr-btn", id: 'publish', disabled: true, data: { confirm: "Vous allez informer les usagers de la clôture de la démarche. Souhaitez-vous continuer ?", disable_with: "Envoi des notifications…", 'closing-notification-target': 'submit'} }
|
||||
%li
|
||||
= link_to t('administrateurs.procedures.close.actions.cancel'), admin_procedures_path, class: 'fr-btn fr-btn--secondary fr-ml-2w'
|
|
@ -47,6 +47,24 @@
|
|||
|
||||
- if !@procedure.procedure_expires_when_termine_enabled?
|
||||
= render partial: 'administrateurs/procedures/suggest_expires_when_termine', locals: { procedure: @procedure }
|
||||
|
||||
- if @procedure.close?
|
||||
.fr-container
|
||||
= render Dsfr::AlertComponent.new(title: 'cette démarche est close', state: (:warning), heading_level: 'h2', extra_class_names: 'fr-my-2w') do |c|
|
||||
- c.with_body do
|
||||
%p
|
||||
Les dossiers en cours peuvent être instruits, mais aucun nouveau dossier ne peut plus être déposé.
|
||||
- if @procedure.closing_reason == 'internal_procedure'
|
||||
- new_procedure = Procedure.find_by(id: @procedure.replaced_by_procedure_id)
|
||||
%p
|
||||
= "Cette démarche est remplacée par une autre démarche dans Démarches simplifiées :"
|
||||
= link_to(new_procedure&.libelle, admin_procedure_path(new_procedure))
|
||||
- if @procedure.closing_reason == 'other'
|
||||
%p
|
||||
= "Plus d'informations dans la #{link_to('page de fermeture', closing_details_path(@procedure.path))}, visible par les usagers."
|
||||
- if @procedure.closing_notification_brouillon? || @procedure.closing_notification_en_cours?
|
||||
= "Un email a été envoyé pour informer les usagers le #{ l(@procedure.closed_at.to_date) }"
|
||||
|
||||
.fr-container
|
||||
%h2= "Gestion de la démarche № #{@procedure.id}"
|
||||
%h3.fr-h6 Indispensable avant publication
|
||||
|
|
16
app/views/layouts/closing_details.html.haml
Normal file
16
app/views/layouts/closing_details.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
- procedure = @procedure || @dossier&.procedure || nil
|
||||
|
||||
- content_for :content do
|
||||
.fr-container.fr-mt-5w
|
||||
.fr-grid-row
|
||||
.fr-col-12.fr-col-md-8.fr-col-offset-md-2
|
||||
.procedure-preview.fr-mb-5w
|
||||
= yield
|
||||
|
||||
- content_for :footer do
|
||||
- if procedure
|
||||
= render partial: 'users/procedure_footer', locals: { procedure: procedure, dossier: @dossier }
|
||||
- else
|
||||
= render partial: 'application/footer'
|
||||
|
||||
= render template: 'layouts/application'
|
4
app/views/user_mailer/notify_after_closing.html.haml
Normal file
4
app/views/user_mailer/notify_after_closing.html.haml
Normal file
|
@ -0,0 +1,4 @@
|
|||
- content_for(:title, @subject)
|
||||
|
||||
%p
|
||||
= simple_format(@content)
|
11
app/views/users/commencer/closing_details.html.haml
Normal file
11
app/views/users/commencer/closing_details.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- content_for(:title, @procedure.libelle)
|
||||
|
||||
.fr-container
|
||||
.fr-grid-row
|
||||
.fr-col-12
|
||||
%h1= t('commencer.closing_details.page_title', libelle: @procedure.libelle, closed_at: @procedure.closed_at.strftime('%d/%m/%Y'))
|
||||
%p
|
||||
= format_text_value(@procedure.closing_details)
|
||||
|
||||
.text-center
|
||||
= image_tag('landing/hero/dematerialiser.svg', "aria-hidden": true)
|
|
@ -54,7 +54,14 @@
|
|||
= render Dsfr::AlertComponent.new(state: :info, size: :sm, extra_class_names: "fr-mb-2w") do |c|
|
||||
- c.with_body do
|
||||
%p
|
||||
= t('views.users.dossiers.dossiers_list.procedure_closed')
|
||||
- if dossier.brouillon? && dossier.procedure.closing_reason == Procedure.closing_reasons.fetch(:internal_procedure)
|
||||
= I18n.t('views.users.dossiers.dossiers_list.procedure_closed.brouillon.internal_procedure', link: commencer_path(dossier.procedure.replaced_by_procedure.path)).html_safe
|
||||
- elsif dossier.brouillon? && dossier.procedure.closing_reason == Procedure.closing_reasons.fetch(:other)
|
||||
= I18n.t('views.users.dossiers.dossiers_list.procedure_closed.brouillon.other', link: closing_details_path(dossier.procedure.path)).html_safe
|
||||
- elsif (dossier.en_construction? || dossier.en_instruction?) && dossier.procedure.closing_reason == Procedure.closing_reasons.fetch(:internal_procedure)
|
||||
= I18n.t('views.users.dossiers.dossiers_list.procedure_closed.en_cours.internal_procedure')
|
||||
- elsif (dossier.en_construction? || dossier.en_instruction?) && dossier.procedure.closing_reason == Procedure.closing_reasons.fetch(:other)
|
||||
= I18n.t('views.users.dossiers.dossiers_list.procedure_closed.en_cours.other', link: closing_details_path(dossier.procedure.path)).html_safe
|
||||
|
||||
- if dossier.pending_correction?
|
||||
= render Dsfr::AlertComponent.new(state: :warning, size: :sm, extra_class_names: "fr-mb-2w") do |c|
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
= render partial: "users/dossiers/replacement_procedure", locals: { replacement_procedure: dossier.procedure.replaced_by_procedure }
|
||||
|
||||
%p
|
||||
= t('users.dossiers.header.banner.contact_service', service_name: dossier.procedure.service.nom, service_phone_number: dossier.procedure.service.telephone, service_email: dossier.procedure.service.email)
|
||||
= t('users.dossiers.header.banner.contact_service_html', service_name: dossier.procedure.service.nom, service_phone_number: Phonelib.parse(dossier.procedure.service.telephone_url).full_national, service_email: dossier.procedure.service.email)
|
||||
|
||||
- if !dossier.brouillon?
|
||||
= render(partial: 'users/dossiers/show/print_dossier', locals: { dossier: dossier })
|
||||
|
|
|
@ -507,6 +507,13 @@ en:
|
|||
shared_with: File shared with
|
||||
deleted: Deleted at %{date}
|
||||
deleted_badge: Deleted
|
||||
procedure_closed:
|
||||
brouillon:
|
||||
internal_procedure: This procedure is closed, you cannot submit this file. We invite you to submit a new one on the <a href="%{link}" target="_blank" rel="noopener noreferrer">procedure</a> which replaces it
|
||||
other: This process is closed, you cannot submit this file. More information <a href="%{link}" target="_blank" rel="noopener noreferrer">here</a>
|
||||
en_cours:
|
||||
internal_procedure: This procedure is closed. Your file has been submitted and can be investigated by the administration
|
||||
other: "This procedure is closed. Your file has been submitted and can be processed by the administration. More information <a href=%{link} target=_blank rel=noopener noreferrer>here</a>"
|
||||
transfers:
|
||||
sender_from_support: Technical support
|
||||
sender_demande_en_cours: "A transfer request is pending on file Nº %{id} to %{email}"
|
||||
|
@ -716,9 +723,6 @@ en:
|
|||
# # etablissement_fail: 'Désolé, nous n’avons pas réussi à enregistrer l’établissement correspondant à ce numéro SIRET'
|
||||
france_connect:
|
||||
connexion: "Error trying to connect to France Connect."
|
||||
procedure_archived:
|
||||
with_service_and_phone_email: This procedure has been closed, it is no longer possible to submit a file. For more information, please contact the service %{service_name}, available at %{service_phone_number} or by email %{service_email}
|
||||
with_organisation_only: This procedure has been closed, it is no longer possible to submit a file. For more information, please contact the organisation %{organisation_name}
|
||||
evil_regexp: The regular expression you have entered is potentially dangerous and could lead to performance issues.
|
||||
mismatch_regexp: The provided example must match the regular expression
|
||||
syntax_error_regexp: The syntax of the regular expression is invalid
|
||||
|
|
|
@ -502,7 +502,13 @@ fr:
|
|||
no_result_reset_search: Réinitialiser la recherche
|
||||
no_result_text_with_filter: ne correspond aux filtres sélectionnés
|
||||
no_result_reset_filter: Réinitialiser les filtres
|
||||
procedure_closed: Cette démarche a été clôturée, vous ne pourrez pas redéposer de dossier à partir du lien de la démarche, contactez votre administration pour plus d’information.
|
||||
procedure_closed:
|
||||
brouillon:
|
||||
internal_procedure: Cette démarche est close, vous ne pouvez pas déposer ce dossier. Nous vous invitons à en déposer un nouveau sur la <a href="%{link}" target="_blank" rel="noopener noreferrer">démarche</a> qui la remplace
|
||||
other: Cette démarche est close, vous ne pouvez pas déposer ce dossier. Plus d'informations <a href="%{link}" target="_blank" rel="noopener noreferrer">ici</a>
|
||||
en_cours:
|
||||
internal_procedure: Cette démarche est close. Votre dossier est bien déposé et peut être instruit par l'administration
|
||||
other: "Cette démarche est close. Votre dossier est bien déposé et peut être instruit par l'administration. Plus d'informations <a href=%{link} target=_blank rel=noopener noreferrer>ici</a>"
|
||||
pending_correction: Ce dossier attend vos corrections. Consultez les modifications à apporter dans la messagerie.
|
||||
depose_at: Déposé le %{date}
|
||||
created_at: Créé le %{date}
|
||||
|
@ -722,9 +728,6 @@ fr:
|
|||
france_connect:
|
||||
connexion: "Erreur lors de la connexion à France Connect."
|
||||
forbidden_html: "Seul-e-s les usagers peuvent se connecter via France Connect. En tant qu’instructeur ou administrateur, nous vous invitons à <a href='%{reset_link}'>réininitialiser votre mot de passe</a>."
|
||||
procedure_archived:
|
||||
with_service_and_phone_email: Cette démarche en ligne a été close, il n’est plus possible de déposer de dossier. Pour plus d’informations veuillez contacter le service %{service_name} au %{service_phone_number} ou par email à %{service_email}
|
||||
with_organisation_only: Cette démarche en ligne a été close, il n’est plus possible de déposer de dossier. Pour plus d’informations veuillez contacter le service %{organisation_name}
|
||||
evil_regexp: L'expression régulière que vous avez entrée est potentiellement dangereuse et pourrait entraîner des problèmes de performance
|
||||
mismatch_regexp: L'exemple doit correspondre à l'expression régulière fournie
|
||||
syntax_error_regexp: La syntaxe de l'expression régulière n'est pas valide
|
||||
|
|
|
@ -14,6 +14,8 @@ en:
|
|||
cadre_juridique: "Exemple: 'https://www.legifrance.gouv.fr/'"
|
||||
old_procedure: This procedure replaces a close? If yes, please indicate the number of the replaced procedure
|
||||
procedure_path: "Personalize if needed the rest of the URL to facilitate access to the procedure. From 3 to 200 characters: lowercase letters, numbers and dashes only"
|
||||
closing_details: Give as many explanations as possible to users about the reason for closing the process
|
||||
closing_details_placeholder: "This procedure has been replaced by the page…\n\nThe guide to the new procedure is available here\n\nFor any further information, contact…\n\nSincerely,"
|
||||
path: Public link
|
||||
organisation: Service
|
||||
description: What is the purpose of this procedure?
|
||||
|
@ -23,6 +25,12 @@ en:
|
|||
lien_site_web: Where will users find the link to the procedure?
|
||||
old_procedure: Replaced procedure number
|
||||
new_procedure: New procedure number
|
||||
replaced_by_procedure_id: New procedure
|
||||
closing_details: Information message on the process closing page
|
||||
closing_reason: Closing reason
|
||||
closing_reasons:
|
||||
other: Other
|
||||
internal_procedure: I replace my procedure with another in Démarches Simplifiées
|
||||
procedure_path: Procedure link to disseminate to users
|
||||
procedure_path_placeholder: procedure-name
|
||||
cadre_juridique: Link to the legal text
|
||||
|
|
|
@ -14,6 +14,8 @@ fr:
|
|||
cadre_juridique: "Exemple: 'https://www.legifrance.gouv.fr/'"
|
||||
old_procedure: Cette démarche remplace une close ? Si oui, veuillez indiquer le n° de la démarche remplacée
|
||||
procedure_path: "Personnalisez si besoin la suite de l’URL, pour faciliter l'accès à la démarche. De 3 à 200 caractères : minuscules, chiffres et tiret seulement"
|
||||
closing_details: Donnez le plus d'explication possible aux usagers sur la raison de la fermeture de la démarche
|
||||
closing_details_placeholder: "Cette démarche a été remplacée par la page…\n\nLe guide de la nouvelle démarche est disponible ici\n\nPour toute information complémentaire, contactez…\n\nCordialement,"
|
||||
path: Lien public
|
||||
organisation: Organisme
|
||||
duree_conservation_dossiers_dans_ds: Durée de conservation des dossiers sur demarches-simplifiees.fr (choisi par un usager)
|
||||
|
@ -27,6 +29,12 @@ fr:
|
|||
lien_site_web: Où les usagers trouveront-ils le lien vers la démarche ?
|
||||
old_procedure: Numéro de la démarche remplacée
|
||||
new_procedure: Numéro de la nouvelle démarche
|
||||
replaced_by_procedure_id: Nouvelle démarche
|
||||
closing_details: Message d'information remplaçant la démarche
|
||||
closing_reason: Raison de la clôture
|
||||
closing_reasons:
|
||||
other: Autre
|
||||
internal_procedure: Je remplace ma démarche par une autre dans Démarches simplifiées
|
||||
procedure_path: Lien de la démarche à diffuser aux usagers
|
||||
procedure_path_placeholder: nom-de-la-demarche
|
||||
cadre_juridique: Lien vers le texte
|
||||
|
|
|
@ -3,9 +3,25 @@ en:
|
|||
procedures:
|
||||
close:
|
||||
page_title: Close the procedure
|
||||
replacement_procedure_title: Is this procedure replaced by an existing one? If yes, please indicate the number of the new procedure
|
||||
replacement_procedure_callout_title: You are about to close a procedure
|
||||
replacement_procedure_callout_content: Files « in construction » or « instructing » can be instructed, but no new files can be filed.
|
||||
actions:
|
||||
close_procedure: Close the procedure
|
||||
close_procedure: Close procedure
|
||||
notify_after_closing: Notify users
|
||||
cancel: Cancel
|
||||
closing_notification:
|
||||
page_title: Alert users
|
||||
page_subtitle: Your procedure has been successfully closed. The link of the procedure now redirects to this <a href="%{closing_path}" target="_blank" rel="noopener noreferrer">closing page</a>.
|
||||
page_subtitle_with_redirection: Your procedure has been successfully closed. The link of the procedure now redirects to this <a href="%{redirection_path}" target="_blank" rel="noopener noreferrer">procedure</a>.
|
||||
callout_content: You can continue to examine the submitted files. If you do not intend to examine these files, we invite you to inform users
|
||||
email_toggle_brouillon:
|
||||
one: You want to send an email to the user with a draft folder
|
||||
other: You want to send an email to %{count} users with a draft folder
|
||||
email_content_brouillon: You want to send an email to users with a draft file
|
||||
email_toggle_en_cours:
|
||||
one: You want to send an email to the user with a submitted file
|
||||
other: You want to send an email to %{count} users with a submitted file
|
||||
email_content_en_cours: You want to send an email to users with a file « in construction » or « instructing »
|
||||
preview_unavailable: Preview is unavailable due to procedure misconfiguration
|
||||
modifications:
|
||||
dossiers_en_construction_and_dossiers_en_instruction: "%{en_construction_count} files « in construction » and %{en_instruction_count} files « instructing » on this procedure version."
|
||||
|
|
|
@ -3,9 +3,25 @@ fr:
|
|||
procedures:
|
||||
close:
|
||||
page_title: Clore la démarche
|
||||
replacement_procedure_title: Cette démarche est-elle remplacée par une existante ? Si oui, veuillez indiquer le n° de la nouvelle démarche
|
||||
replacement_procedure_callout_title: Vous êtes sur le point de clore une démarche
|
||||
replacement_procedure_callout_content: Les dossiers en cours pourront être instruits, mais aucun nouveau dossier ne pourra plus être déposé.
|
||||
actions:
|
||||
close_procedure: Clore la démarche
|
||||
notify_after_closing: Informer les usagers
|
||||
cancel: Retour
|
||||
closing_notification:
|
||||
page_title: Alerter les usagers
|
||||
page_subtitle: Votre démarche est close. Le lien de votre démarche redirige désormais vers cette <a href="%{closing_path}" target="_blank" rel="noopener noreferrer">page de fermeture</a>.
|
||||
page_subtitle_with_redirection: Votre démarche est close. Le lien public redirige désormais vers cette <a href="%{redirection_path}" target="_blank" rel="noopener noreferrer">démarche</a>.
|
||||
callout_content: Vous avez la possibilité de continuer à instruire les dossiers déposés. Si vous n’avez pas l’intention d’instruire ces dossiers, nous vous invitons à en informer les usagers.
|
||||
email_toggle_brouillon:
|
||||
one: Souhaitez-vous envoyer un email à l'utilisateur avec un dossier en brouillon ?
|
||||
other: Souhaitez-vous envoyer un email aux %{count} utilisateurs avec un dossier en brouillon ?
|
||||
email_content_brouillon: Contenu de l'email
|
||||
email_toggle_en_cours:
|
||||
one : Souhaitez-vous envoyer un email à l'utilisateur avec un dossier déposé ?
|
||||
other: Souhaitez-vous envoyer un email aux %{count} utilisateurs avec un dossier déposé ?
|
||||
email_content_en_cours: Contenu de l'email
|
||||
preview_unavailable: Aperçu non disponible car la démarche est mal configurée
|
||||
modifications:
|
||||
dossiers_en_construction_and_dossiers_en_instruction: Il y a %{en_construction_count} dossiers « en construction » et %{en_instruction_count} dossiers « en instruction » sur cette version de la démarche.
|
||||
|
|
|
@ -21,3 +21,5 @@ en:
|
|||
other: "Your last %{count} created files :"
|
||||
already_created_details_html:
|
||||
"N° %{id}, created %{created_at} ago and %{state}"
|
||||
closing_details:
|
||||
page_title: "Procedure %{libelle} is closed since %{closed_at}"
|
||||
|
|
|
@ -21,3 +21,5 @@ fr:
|
|||
other: "Vos %{count} derniers dossiers créés :"
|
||||
already_created_details_html:
|
||||
"N° %{id}, créé il y a %{created_at} et %{state}"
|
||||
closing_details:
|
||||
page_title: "La démarche %{libelle} est close depuis le %{closed_at}"
|
||||
|
|
|
@ -11,7 +11,7 @@ en:
|
|||
procedure_close_content: You can still consult your file, but it will not be processed by the administration
|
||||
new_procedure_link: see the procedure
|
||||
new_procedure_content: "A new procedure is available, consult it here:"
|
||||
contact_service: For more information, please contact the service %{service_name}, available at %{service_phone_number} or by email %{service_email}
|
||||
contact_service_html: For more information, please contact the service %{service_name}, available at %{service_phone_number} or by email to <a href="mailto:%{service_email}">%{service_email}</a>
|
||||
states:
|
||||
brouillon: Your file is still in draft and will soon expire. So it will be deleted soon without being instructed. If you want to pursue your procedure you can submit it now. Otherwise you are able to delay its expiration by clicking on the underneath button.
|
||||
en_construction: Your file is pending for instruction. The maximum delay is %{nominal_duration_months} months, but you can extend the duration by clicking on the underneath button.
|
||||
|
|
|
@ -10,7 +10,7 @@ fr:
|
|||
procedure_close_content: "Vous pouvez toujours consulter votre dossier, mais il ne sera pas traité par l’administration"
|
||||
new_procedure_link: voir la démarche
|
||||
new_procedure_content: "Une nouvelle démarche est disponible, consultez-la ici :"
|
||||
contact_service: Pour plus d’informations, veuillez vous rapprocher du service %{service_name}, disponible au %{service_phone_number} ou par email %{service_email}
|
||||
contact_service_html: Pour plus d’informations, 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
|
||||
states:
|
||||
brouillon: Votre dossier est en brouillon, mais va bientôt expirer. Cela signifie qu’il 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.
|
||||
|
|
|
@ -382,6 +382,7 @@ Rails.application.routes.draw do
|
|||
post 'accept_merge' => 'profil#accept_merge'
|
||||
post 'refuse_merge' => 'profil#refuse_merge'
|
||||
delete 'france_connect_information' => 'profil#destroy_fci'
|
||||
get 'fermeture/:path', to: 'commencer#closing_details', as: :closing_details
|
||||
end
|
||||
|
||||
get 'procedures/:id/logo', to: 'procedures#logo', as: :procedure_logo
|
||||
|
@ -600,6 +601,8 @@ Rails.application.routes.draw do
|
|||
put 'publish_revision' => 'procedures#publish_revision', as: :publish_revision
|
||||
get 'transfert' => 'procedures#transfert', as: :transfert
|
||||
get 'close' => 'procedures#close', as: :close
|
||||
get 'closing_notification' => 'procedures#closing_notification', as: :closing_notification
|
||||
post 'notify_after_closing' => 'procedures#notify_after_closing', as: :notify_after_closing
|
||||
get 'confirmation' => 'procedures#confirmation', as: :confirmation
|
||||
post 'transfer' => 'procedures#transfer', as: :transfer
|
||||
resources :mail_templates, only: [:edit, :update, :show]
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class AddClosingReasonAndClosingDetails < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :procedures, :closing_reason, :string
|
||||
add_column :procedures, :closing_details, :string
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class AddClosingNotificationsToProcedure < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :procedures, :closing_notification_brouillon, :boolean, default: false, null: false
|
||||
add_column :procedures, :closing_notification_en_cours, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
|
@ -856,6 +856,10 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_27_163855) do
|
|||
t.jsonb "chorus", default: {}, null: false
|
||||
t.boolean "cloned_from_library", default: false
|
||||
t.datetime "closed_at", precision: nil
|
||||
t.string "closing_details"
|
||||
t.boolean "closing_notification_brouillon", default: false, null: false
|
||||
t.boolean "closing_notification_en_cours", default: false, null: false
|
||||
t.string "closing_reason"
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.string "declarative_with_state"
|
||||
t.bigint "defaut_groupe_instructeur_id"
|
||||
|
|
|
@ -720,36 +720,60 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
|
||||
context 'when the admin is an owner of the procedure without procedure replacement' do
|
||||
before do
|
||||
put :archive, params: { procedure_id: procedure.id }
|
||||
put :archive, params: { procedure_id: procedure.id, procedure: { closing_reason: 'other' } }
|
||||
procedure.reload
|
||||
end
|
||||
|
||||
it 'archives the procedure' do
|
||||
expect(procedure.close?).to be_truthy
|
||||
expect(response).to redirect_to :admin_procedures
|
||||
expect(response).to redirect_to admin_procedure_path(procedure.id)
|
||||
expect(flash[:notice]).to have_content 'Démarche close'
|
||||
end
|
||||
|
||||
it 'does not have any replacement procedure' do
|
||||
expect(procedure.replaced_by_procedure).to be_nil
|
||||
expect(procedure.closing_reason).to eq('other')
|
||||
end
|
||||
|
||||
context 'the admin can notify users if there are file in brouillon or en_cours' do
|
||||
let!(:procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2, administrateur: admin, lien_site_web: lien_site_web) }
|
||||
it 'archives the procedure and redirects to page to notify users' do
|
||||
expect(procedure.close?).to be_truthy
|
||||
expect(response).to redirect_to :admin_procedure_closing_notification
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the admin is an owner of the procedure with procedure replacement' do
|
||||
context 'when the admin is an owner of the procedure with procedure replacement in DS' do
|
||||
let(:procedure) { create(:procedure_with_dossiers, :published, administrateur: admin, lien_site_web: lien_site_web) }
|
||||
let(:new_procedure) { create(:procedure, :published, administrateur: admin, lien_site_web: lien_site_web) }
|
||||
before do
|
||||
put :archive, params: { procedure_id: procedure.id, new_procedure: new_procedure }
|
||||
put :archive, params: { procedure_id: procedure.id, procedure: { closing_reason: 'internal_procedure', replaced_by_procedure_id: new_procedure.id } }
|
||||
procedure.reload
|
||||
end
|
||||
|
||||
it 'archives the procedure' do
|
||||
expect(procedure.close?).to be_truthy
|
||||
expect(response).to redirect_to :admin_procedures
|
||||
expect(flash[:notice]).to have_content 'Démarche close'
|
||||
expect(response).to redirect_to admin_procedure_closing_notification_path
|
||||
end
|
||||
|
||||
it 'does have a replacement procedure' do
|
||||
expect(procedure.replaced_by_procedure).to eq(new_procedure)
|
||||
expect(procedure.closing_reason).to eq('internal_procedure')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the admin is an owner of the procedure with procedure replacement outside DS' do
|
||||
let(:new_procedure) { create(:procedure, :published, administrateur: admin, lien_site_web: lien_site_web) }
|
||||
before do
|
||||
put :archive, params: { procedure_id: procedure.id, procedure: { closing_reason: 'other', closing_details: "Sorry it's closed" } }
|
||||
procedure.reload
|
||||
end
|
||||
|
||||
it 'archives the procedure' do
|
||||
expect(procedure.close?).to be_truthy
|
||||
expect(response).to redirect_to admin_procedure_path(procedure.id)
|
||||
expect(flash[:notice]).to have_content 'Démarche close'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -760,7 +784,7 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
sign_out(admin.user)
|
||||
sign_in(admin_2.user)
|
||||
|
||||
put :archive, params: { procedure_id: procedure.id }
|
||||
put :archive, params: { procedure_id: procedure.id, procedure: { closing_reason: 'other' } }
|
||||
procedure.reload
|
||||
end
|
||||
|
||||
|
@ -769,6 +793,42 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
expect(flash[:alert]).to have_content 'Démarche inexistante'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the admin is not an owner of the new procedure in DS' do
|
||||
let(:admin_2) { create(:administrateur) }
|
||||
let(:other_admin_procedure) { create(:procedure, :with_all_champs, administrateurs: [admin_2]) }
|
||||
|
||||
before do
|
||||
put :archive, params: { procedure_id: procedure.id, procedure: { closing_reason: 'internal_procedure', replaced_by_procedure_id: other_admin_procedure.id } }
|
||||
procedure.reload
|
||||
end
|
||||
|
||||
it 'closes the procedure without redirection to the new procedure in DS' do
|
||||
expect(response).to redirect_to admin_procedure_path(procedure.id)
|
||||
expect(flash[:notice]).to have_content 'Démarche close'
|
||||
expect(procedure.replaced_by_procedure).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #notify_after_closing' do
|
||||
let(:procedure_closed) { create(:procedure_with_dossiers, :closed, administrateurs: [admin]) }
|
||||
let(:user_ids) { [procedure_closed.dossiers.first.user.id] }
|
||||
let(:email_content) { "La démarche a fermé" }
|
||||
|
||||
subject do
|
||||
post :notify_after_closing, params: { procedure_id: procedure_closed.id, procedure: { closing_notification_brouillon: true }, email_content_brouillon: email_content }
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(admin.user)
|
||||
end
|
||||
|
||||
it 'redirects to admin procedures' do
|
||||
expect { subject }.to have_enqueued_job(SendClosingNotificationJob).with(user_ids, email_content, procedure_closed)
|
||||
expect(flash.notice).to eq("Les emails sont en cours d'envoi")
|
||||
expect(response).to redirect_to :admin_procedures
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
|
@ -1055,6 +1115,27 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
context 'procedure was closed and is re opened' do
|
||||
before do
|
||||
procedure.publish!
|
||||
procedure.update!(closing_reason: 'internal_procedure', replaced_by_procedure_id: procedure2.id)
|
||||
procedure.close!
|
||||
procedure.update!(closing_notification_brouillon: true, closing_notification_en_cours: true)
|
||||
perform_request
|
||||
procedure.reload
|
||||
procedure2.reload
|
||||
end
|
||||
|
||||
it 'publish the given procedure and reset closing params' do
|
||||
expect(procedure.publiee?).to be_truthy
|
||||
expect(procedure.path).to eq(path)
|
||||
expect(procedure.closing_reason).to be_nil
|
||||
expect(procedure.replaced_by_procedure_id).to be_nil
|
||||
expect(procedure.closing_notification_brouillon).to be_falsy
|
||||
expect(procedure.closing_notification_en_cours).to be_falsy
|
||||
end
|
||||
end
|
||||
|
||||
context 'procedure path exists and is not owned by current administrator' do
|
||||
let(:path) { procedure3.path }
|
||||
let(:lien_site_web) { 'http://mon-site.gouv.fr' }
|
||||
|
|
|
@ -42,7 +42,7 @@ describe Users::CommencerController, type: :controller do
|
|||
published_procedure.organisation = "hello"
|
||||
published_procedure.close!
|
||||
get :commencer, params: { path: published_procedure.path }
|
||||
expect(response).to redirect_to(root_path)
|
||||
expect(response).to redirect_to(closing_details_path(published_procedure.path))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -51,7 +51,7 @@ describe Users::CommencerController, type: :controller do
|
|||
published_procedure.service = create(:service)
|
||||
published_procedure.close!
|
||||
get :commencer, params: { path: published_procedure.path }
|
||||
expect(response).to redirect_to(root_path)
|
||||
expect(response).to redirect_to(closing_details_path(published_procedure.path))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ class UserMailerPreview < ActionMailer::Preview
|
|||
UserMailer.notify_inactive_close_to_deletion(user)
|
||||
end
|
||||
|
||||
def notify_after_closing
|
||||
UserMailer.notify_after_closing([user])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user
|
||||
|
|
|
@ -127,4 +127,22 @@ RSpec.describe UserMailer, type: :mailer do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.notify_after_closing' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:content) { "Bonjour,\r\nsaut de ligne" }
|
||||
subject { described_class.notify_after_closing(user, content, procedure) }
|
||||
|
||||
it { expect(subject.to).to eq([user.email]) }
|
||||
it { expect(subject.body).to include("Clôture d'une démarche sur Démarches simplifiées") }
|
||||
it { expect(subject.body).to include("Bonjour,\r\n<br />saut de ligne") }
|
||||
|
||||
context 'when perform_later is called' do
|
||||
let(:custom_queue) { 'low_priority' }
|
||||
before { ENV['BULK_EMAIL_QUEUE'] = custom_queue }
|
||||
it 'enqueues email is custom queue for low priority delivery' do
|
||||
expect { subject.deliver_later }.to have_enqueued_job.on_queue(custom_queue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -178,6 +178,20 @@ describe Procedure do
|
|||
it { is_expected.to allow_value('Demande de subvention').for(:libelle) }
|
||||
end
|
||||
|
||||
context 'closing procedure' do
|
||||
context 'without replacing procedure in DS' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
context 'valid' do
|
||||
before do
|
||||
procedure.update!(closing_details: "Bonjour,\nLa démarche est désormais hébergée sur une autre plateforme\nCordialement", closing_reason: Procedure.closing_reasons.fetch(:other))
|
||||
end
|
||||
|
||||
it { expect(procedure).to be_valid }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'description' do
|
||||
it { is_expected.not_to allow_value(nil).for(:description) }
|
||||
it { is_expected.not_to allow_value('').for(:description) }
|
||||
|
|
96
spec/system/administrateurs/procedure_closing_spec.rb
Normal file
96
spec/system/administrateurs/procedure_closing_spec.rb
Normal file
|
@ -0,0 +1,96 @@
|
|||
require 'system/administrateurs/procedure_spec_helper'
|
||||
|
||||
describe 'Closing a procedure', js: true do
|
||||
include ProcedureSpecHelper
|
||||
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
let!(:procedure) do
|
||||
create(:procedure_with_dossiers,
|
||||
:published,
|
||||
:with_path,
|
||||
:with_type_de_champ,
|
||||
:with_service,
|
||||
:with_zone,
|
||||
administrateur: administrateur,
|
||||
dossiers_count: 2)
|
||||
end
|
||||
|
||||
let!(:other_procedure) do
|
||||
create(:procedure,
|
||||
:published,
|
||||
:with_path,
|
||||
administrateur: administrateur)
|
||||
end
|
||||
|
||||
before do
|
||||
login_as administrateur.user, scope: :user
|
||||
end
|
||||
|
||||
context 'when procedure is replaced in DS' do
|
||||
scenario 'the link of the new procedure is added in show page' do
|
||||
visit admin_procedure_close_path(procedure)
|
||||
|
||||
expect(page).to have_current_path(admin_procedure_close_path(procedure))
|
||||
|
||||
expect(page).to have_text('Clore la démarche')
|
||||
|
||||
select('Je remplace ma démarche par une autre dans Démarches simplifiées')
|
||||
|
||||
select("#{other_procedure.libelle} (#{other_procedure.id})")
|
||||
|
||||
accept_alert do
|
||||
within('form') { click_on 'Clore la démarche' }
|
||||
end
|
||||
|
||||
procedure.reload
|
||||
|
||||
expect(page).to have_current_path(admin_procedure_closing_notification_path(procedure))
|
||||
|
||||
expect(page).to have_text('Votre démarche est close')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when procedure is not replaced in DS' do
|
||||
scenario 'the admin can notify users' do
|
||||
visit admin_procedure_close_path(procedure)
|
||||
|
||||
expect(page).to have_current_path(admin_procedure_close_path(procedure))
|
||||
|
||||
expect(page).to have_text('Clore la démarche')
|
||||
|
||||
select('Autre')
|
||||
|
||||
fill_in("Message d'information remplaçant la démarche", with: "Bonjour,\nLa démarche est maintenant sur www.autre-site.fr\nCordialement")
|
||||
|
||||
accept_alert do
|
||||
within('form') { click_on 'Clore la démarche' }
|
||||
end
|
||||
|
||||
procedure.reload
|
||||
|
||||
expect(page).to have_current_path(admin_procedure_closing_notification_path(procedure))
|
||||
|
||||
expect(page).to have_text('Votre démarche est close')
|
||||
|
||||
expect(page).to have_text("Souhaitez-vous envoyer un email à l'utilisateur avec un dossier en brouillon ?")
|
||||
|
||||
check("Souhaitez-vous envoyer un email à l'utilisateur avec un dossier en brouillon ?")
|
||||
|
||||
expect(page).to have_text ("Contenu de l'email")
|
||||
|
||||
fill_in('email_content_brouillon', with: "La démarche a fermé.")
|
||||
|
||||
accept_alert do
|
||||
click_on 'Informer les usagers'
|
||||
end
|
||||
|
||||
expect(page).to have_current_path(admin_procedures_path)
|
||||
|
||||
visit admin_procedure_path(procedure)
|
||||
|
||||
procedure.reload
|
||||
|
||||
expect(page).to have_text("Un email a été envoyé pour informer les usagers le #{procedure.closed_at.strftime('%d/%m/%Y')}")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
module Maintenance
|
||||
RSpec.describe BackfillClosingReasonInClosedProceduresTask do
|
||||
describe "#process" do
|
||||
subject(:process) { described_class.process(procedure) }
|
||||
|
||||
context 'with a closed and replaced procedure' do
|
||||
let(:published_procedure) { create(:procedure, :published) }
|
||||
let(:procedure) { create(:procedure, :closed, replaced_by_procedure_id: published_procedure.id) }
|
||||
|
||||
it 'fills closing_reason with internal_procedure' do
|
||||
subject
|
||||
expect(procedure.closing_reason).to eq Procedure.closing_reasons.fetch(:internal_procedure)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a closed and not replaced procedure' do
|
||||
let(:procedure) { create(:procedure, :closed) }
|
||||
|
||||
it 'fills closing_reason with other' do
|
||||
subject
|
||||
expect(procedure.closing_reason).to eq Procedure.closing_reasons.fetch(:other)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue