feat(instructeur): can flag a dossier as "pending corrections"

This commit is contained in:
Colin Darie 2023-03-14 17:23:17 +01:00
parent 5d61c6fa35
commit ca3b127942
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
13 changed files with 254 additions and 32 deletions

View file

@ -7,3 +7,4 @@ en:
automatic_email: Automatic email
you: You
deleted_body: Message deleted
flagged_pending_corrections: Modification requested

View file

@ -7,3 +7,4 @@ fr:
automatic_email: Email automatique
you: Vous
deleted_body: Message supprimé
flagged_pending_corrections: Modification demandée

View file

@ -6,6 +6,9 @@
= commentaire_issuer
- if commentaire_from_guest?
%span.fr-text--xs.fr-text-mention--grey.font-weight-normal= t('.guest')
- if commentaire.flagged_pending_corrections?
%span.fr-badge.fr-badge--sm.fr-badge--info
= t('.flagged_pending_corrections')
%span.date{ class: ["fr-text--xs", "fr-text-mention--grey", "font-weight-normal", highlight_if_unseen_class], data: scroll_to_target }
= commentaire_date
.rich-text

View file

@ -223,6 +223,34 @@ module Instructeurs
render :change_state
end
def pending_corrections
message, piece_jointe = params.require(:dossier).permit(:motivation, :justificatif_motivation).values
if message.empty?
flash.alert = "Vous devez préciser quelle modification est attendue."
elsif !dossier.may_flag_as_pending_correction?
flash.alert = dossier.termine? ? "Impossible de demander de corriger un dossier terminé." : "Le dossier est déjà en attente de correction."
else
commentaire = CommentaireService.create(current_instructeur, dossier, { body: message, piece_jointe: })
dossier.flag_as_pending_correction!(commentaire)
dossier.update!(last_commentaire_updated_at: Time.zone.now)
current_instructeur.follow(dossier)
flash.notice = "Dossier marqué comme en attente de correction."
end
respond_to do |format|
format.turbo_stream do
@dossier = dossier
render :change_state
end
format.html do
redirect_back(fallback_location: instructeur_procedure_path(procedure))
end
end
end
def create_commentaire
@commentaire = CommentaireService.create(current_instructeur, dossier, commentaire_params)

View file

@ -95,6 +95,10 @@ class Commentaire < ApplicationRecord
update! body: ''
end
def flagged_pending_corrections?
DossierResolution.exists?(commentaire: self)
end
private
def notify

View file

@ -4,6 +4,22 @@ module DossierResolvableConcern
included do
has_many :resolutions, class_name: 'DossierResolution', dependent: :destroy
def flag_as_pending_correction!(commentaire)
return unless may_flag_as_pending_correction?
resolutions.create(commentaire:)
return if en_construction?
repasser_en_construction!(instructeur: commentaire.instructeur)
end
def may_flag_as_pending_correction?
return false if resolutions.pending.exists?
en_construction? || may_repasser_en_construction?
end
def pending_resolution?
# We don't want to show any alert if user is not allowed to modify the dossier
return false unless en_construction?

View file

@ -1,35 +1,56 @@
- if dossier.en_instruction?
- if dossier.en_instruction? || (dossier.en_construction? && dossier.may_flag_as_pending_correction?)
= render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: { turbo_force: :server } }, button_options: { class: [button_or_label_class(dossier)]}, role: dossier.en_instruction? ? :region : :menu) do |menu|
- menu.with_button_inner_html do
Instruire le dossier
= dossier.en_instruction? ? "Instruire le dossier" : "Demander une modification"
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'accept');", role: 'menuitem') do
%span.icon.accept
.dropdown-description
%h4 Accepter
Lusager sera informé que son dossier a été accepté
- if dossier.en_instruction?
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'accept');", role: 'menuitem') do
%span.icon.accept
.dropdown-description
%h4 Accepter
Lusager sera informé que son dossier a été accepté
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est accepté (facultatif)', popup_class: 'accept', process_action: 'accepter', title: 'Accepter', confirm: "Confirmez-vous l'acceptation ce dossier ?" }
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est accepté (facultatif)', popup_class: 'accept', process_action: 'accepter', title: 'Accepter', confirm: "Confirmez-vous l'acceptation ce dossier ?" }
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'without-continuation');", role: 'menuitem') do
%span.icon.without-continuation
.dropdown-description
%h4 Classer sans suite
Lusager sera informé que son dossier a été classé sans suite
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'without-continuation');", role: 'menuitem') do
%span.icon.without-continuation
.dropdown-description
%h4 Classer sans suite
Lusager sera informé que son dossier a été classé sans suite
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est classé sans suite (obligatoire)', popup_class: 'without-continuation', process_action: 'classer_sans_suite', title: 'Classer sans suite', confirm: 'Confirmez-vous le classement sans suite de ce dossier ?' }
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est classé sans suite (obligatoire)', popup_class: 'without-continuation', process_action: 'classer_sans_suite', title: 'Classer sans suite', confirm: 'Confirmez-vous le classement sans suite de ce dossier ?' }
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'refuse');", role: 'menuitem') do
%span.icon.refuse
.dropdown-description
%h4 Refuser
Lusager sera informé que son dossier a été refusé
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'refuse');", role: 'menuitem') do
%span.icon.refuse
.dropdown-description
%h4 Refuser
Lusager sera informé que son dossier a été refusé
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est refusé (obligatoire)', popup_class: 'refuse', process_action: 'refuser', title: 'Refuser', confirm: 'Confirmez-vous le refus de ce dossier ?' }
- menu.with_item(class: "hidden inactive form-inside") do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est refusé (obligatoire)', popup_class: 'refuse', process_action: 'refuser', title: 'Refuser', confirm: 'Confirmez-vous le refus de ce dossier ?' }
- if dossier.may_flag_as_pending_correction?
- menu.with_item do
= link_to('#', onclick: "DS.showMotivation(event, 'pending_corrections');", role: 'menuitem') do
%span.fr-icon.fr-icon-error-warning-line.fr-text-default--info{ "aria-hidden": "true" }
.dropdown-description
%h4 Demander une modification
Lusager sera informé que des modifications sont attendues
- menu.with_item(class: class_names("inactive form-inside": true, hidden: dossier.en_instruction?)) do
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier,
visible: !dossier.en_instruction?,
form_path: pending_corrections_instructeur_dossier_path(dossier.procedure, dossier),
placeholder: 'Expliquez au demandeur quelles modifications sont attendues',
popup_class: 'pending_corrections',
button_justificatif_label: "Ajouter une pièce jointe (facultatif)",
process_button: dossier.en_construction? ? 'Valider' : 'Valider et repasser en construction',
process_action: nil,
title: 'Marquer en attente de corrections',
confirm: 'Envoyer la demande de corrections ?'}

View file

@ -1,5 +1,5 @@
.motivation.hidden{ class: popup_class }
= form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo: true, turbo_confirm: confirm }, method: :post, multipart: true) do
.motivation{ class: class_names(popup_class => true, hidden: !defined?(visible) || !visible) }
= form_tag(defined?(form_path) ? form_path : terminer_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo: true, turbo_confirm: confirm }, method: :post, multipart: true) do
- if title == 'Accepter'
= text_area :dossier, :motivation, class: 'fr-input', placeholder: placeholder, required: false
- if dossier.attestation_template&.activated?
@ -28,11 +28,11 @@
- else
= text_area :dossier, :motivation, class: 'fr-input', placeholder: placeholder, required: true
.optional-justificatif{ id: "justificatif_motivation_suggest_#{popup_class}", onclick: "DS.showImportJustificatif('#{popup_class}');" }
%button.fr-btn.fr-btn--tertiary-no-outline.fr-btn--icon-left.fr-icon-attachment-line.fr-ml-0{ type: 'button', onclick: "DS.showImportJustificatif('accept');" } Ajouter un justificatif (optionnel)
%button.fr-btn.fr-btn--tertiary-no-outline.fr-btn--icon-left.fr-icon-attachment-line.fr-ml-0{ type: 'button', onclick: "DS.showImportJustificatif('accept');" }= defined?(button_justificatif_label) ? button_justificatif_label : "Ajouter un justificatif (optionnel)"
.hidden{ id: "justificatif_motivation_import_#{popup_class}" }
= file_field :dossier, :justificatif_motivation, direct_upload: true, id: "dossier_justificatif_motivation_#{popup_class}",onchange: "DS.showDeleteJustificatif('#{popup_class}');"
.hidden.js_delete_motivation{ id: "delete_motivation_import_#{popup_class}" }
%button.fr-btn.fr-btn--tertiary-no-outline.fr-btn--icon-left.fr-icon-delete-line.fr-ml-0.fr-mt-1w{ type: 'button', onclick: "DS.deleteJustificatif('#{popup_class}');" } Supprimer le justificatif
.fr-mt-2w
= button_tag "Annuler", type: :reset, class: 'fr-btn fr-btn--secondary', onclick: 'DS.motivationCancel();'
= button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'fr-btn fr-mr-0', title: title
= button_tag defined?(process_button) ? process_button : 'Valider la décision', name: :process_action, value: process_action, class: 'fr-btn fr-mr-0', title: title