diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb
index 5642d1fda..02640933e 100644
--- a/app/controllers/instructeurs/procedures_controller.rb
+++ b/app/controllers/instructeurs/procedures_controller.rb
@@ -224,19 +224,18 @@ module Instructeurs
def email_usagers
@procedure = procedure
- @commentaire = Commentaire.new
- @email_usagers_dossiers = email_usagers_dossiers
- @dossiers_count = @email_usagers_dossiers.count
- @groupe_instructeurs = email_usagers_groupe_instructeurs_label
- @bulk_messages = BulkMessage.includes(:groupe_instructeurs).where(groupe_instructeurs: { id: current_instructeur.groupe_instructeur_ids, procedure: procedure })
+ @bulk_messages = BulkMessage.includes(:groupe_instructeurs).where(groupe_instructeurs: { procedure: procedure })
+ @bulk_message = current_instructeur.bulk_messages.build
+ @dossiers_without_groupe_count = procedure.dossiers.state_brouillon.for_groupe_instructeur(nil).count
end
def create_multiple_commentaire
@procedure = procedure
errors = []
-
- email_usagers_dossiers.each do |dossier|
- commentaire = CommentaireService.create(current_instructeur, dossier, commentaire_params)
+ bulk_message = current_instructeur.bulk_messages.build(bulk_message_params)
+ dossiers = procedure.dossiers.state_brouillon.for_groupe_instructeur(nil)
+ dossiers.each do |dossier|
+ commentaire = CommentaireService.create(current_instructeur, dossier, bulk_message_params.except(:targets))
if commentaire.errors.empty?
commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
else
@@ -244,8 +243,15 @@ module Instructeurs
end
end
- valid_dossiers_count = email_usagers_dossiers.count - errors.count
- create_bulk_message_mail(valid_dossiers_count, Dossier.states.fetch(:brouillon))
+ valid_dossiers_count = dossiers.count - errors.count
+ bulk_message.assign_attributes(
+ dossier_count: valid_dossiers_count,
+ dossier_state: Dossier.states.fetch(:brouillon),
+ sent_at: Time.zone.now,
+ instructeur_id: current_instructeur.id,
+ groupe_instructeurs: GroupeInstructeur.for_dossiers(dossiers)
+ )
+ bulk_message.save!
if errors.empty?
flash[:notice] = "Tous les messages ont été envoyés avec succès"
@@ -262,18 +268,6 @@ module Instructeurs
private
- def create_bulk_message_mail(dossier_count, dossier_state)
- BulkMessage.create(
- dossier_count: dossier_count,
- dossier_state: dossier_state,
- body: commentaire_params[:body],
- sent_at: Time.zone.now,
- instructeur_id: current_instructeur.id,
- piece_jointe: commentaire_params[:piece_jointe],
- groupe_instructeurs: email_usagers_groupe_instructeurs
- )
- end
-
def assign_to_params
params.require(:assign_to)
.permit(:instant_expert_avis_email_notifications_enabled, :instant_email_dossier_notifications_enabled, :instant_email_message_notifications_enabled, :daily_email_notifications_enabled, :weekly_email_notifications_enabled)
@@ -355,20 +349,8 @@ module Instructeurs
@current_filters ||= procedure_presentation.filters.fetch(statut, [])
end
- def email_usagers_dossiers
- procedure.dossiers.state_brouillon.where(groupe_instructeur: current_instructeur.groupe_instructeur_ids).includes(:groupe_instructeur)
- end
-
- def email_usagers_groupe_instructeurs_label
- email_usagers_dossiers.map(&:groupe_instructeur).uniq.map(&:label)
- end
-
- def email_usagers_groupe_instructeurs
- email_usagers_dossiers.map(&:groupe_instructeur).uniq
- end
-
- def commentaire_params
- params.require(:commentaire).permit(:body, :piece_jointe)
+ def bulk_message_params
+ params.require(:bulk_message).permit(:body)
end
end
end
diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb
index 92e9c25b5..91419ad23 100644
--- a/app/controllers/users/dossiers_controller.rb
+++ b/app/controllers/users/dossiers_controller.rb
@@ -541,6 +541,7 @@ module Users
def update_dossier_and_compute_errors
errors = []
+
@dossier.assign_attributes(champs_public_params)
if @dossier.champs_public_all.any?(&:changed_for_autosave?)
@dossier.last_champ_updated_at = Time.zone.now
diff --git a/app/models/bulk_message.rb b/app/models/bulk_message.rb
index 6de6905a3..8f54de120 100644
--- a/app/models/bulk_message.rb
+++ b/app/models/bulk_message.rb
@@ -1,5 +1,4 @@
class BulkMessage < ApplicationRecord
belongs_to :instructeur
has_and_belongs_to_many :groupe_instructeurs, -> { order(:label) }
- has_one_attached :piece_jointe
end
diff --git a/app/models/commentaire.rb b/app/models/commentaire.rb
index 4cac74bf1..4edbb0110 100644
--- a/app/models/commentaire.rb
+++ b/app/models/commentaire.rb
@@ -1,8 +1,6 @@
class Commentaire < ApplicationRecord
include Discard::Model
-
belongs_to :dossier, inverse_of: :commentaires, touch: true, optional: false
-
belongs_to :instructeur, inverse_of: :commentaires, optional: true
belongs_to :expert, inverse_of: :commentaires, optional: true
has_one :dossier_correction, inverse_of: :commentaire, dependent: :nullify
diff --git a/app/models/dossier.rb b/app/models/dossier.rb
index 12050c35a..d55bf99e2 100644
--- a/app/models/dossier.rb
+++ b/app/models/dossier.rb
@@ -215,7 +215,7 @@ class Dossier < ApplicationRecord
}
scope :for_procedure_preview, -> { where(for_procedure_preview: true) }
scope :for_editing_fork, -> { where.not(editing_fork_origin_id: nil) }
-
+ scope :for_groupe_instructeur, -> (groupe_instructeurs) { where(groupe_instructeur: groupe_instructeurs) }
scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) }
scope :order_by_created_at, -> (order = :asc) { order(depose_at: order, created_at: order, id: order) }
scope :updated_since, -> (since) { where('dossiers.updated_at >= ?', since) }
diff --git a/app/models/groupe_instructeur.rb b/app/models/groupe_instructeur.rb
index 87224cf7b..cad3b2638 100644
--- a/app/models/groupe_instructeur.rb
+++ b/app/models/groupe_instructeur.rb
@@ -30,7 +30,7 @@ class GroupeInstructeur < ApplicationRecord
scope :for_api_v2, -> { includes(procedure: [:administrateurs]) }
scope :active, -> { where(closed: false) }
scope :closed, -> { where(closed: true) }
-
+ scope :for_dossiers, -> (dossiers) { joins(:dossiers).where(dossiers: dossiers).distinct(:id) }
def add(instructeur)
return if instructeur.nil?
return if in?(instructeur.groupe_instructeurs)
diff --git a/app/views/instructeurs/procedures/email_usagers.html.haml b/app/views/instructeurs/procedures/email_usagers.html.haml
index 115a47a33..61af93444 100644
--- a/app/views/instructeurs/procedures/email_usagers.html.haml
+++ b/app/views/instructeurs/procedures/email_usagers.html.haml
@@ -3,30 +3,35 @@
= render partial: 'administrateurs/breadcrumbs',
locals: { steps: [[@procedure.libelle.truncate_words(10), instructeur_procedure_path(@procedure)],
[t('.contact_users')]] }
-.messagerie.container
- - if @email_usagers_dossiers.present?
- %p.notice.mb-2.mt-4
- = t('.notice', dossiers_count: pluralize(@dossiers_count, 'personne'), groupe_instructeurs: @groupe_instructeurs.join(', '))
+.messagerie.fr-container
+ %h1 Contacter les usagers
+ %p.fr-highlight
+ = t('.hint', count: @dossiers_without_groupe_count).html_safe
- = render partial: 'shared/dossiers/messages/form', locals: { commentaire: @commentaire, form_url: create_multiple_commentaire_instructeur_procedure_path(@procedure), disable_piece_jointe: true }
+ - if @dossiers_without_groupe_count.positive?
+ = form_for(@bulk_message, url: create_multiple_commentaire_instructeur_procedure_path, html: { data: { controller: 'persisted-form', persisted_form_key_value: dom_id(@procedure, :bulk_message) } }) do |f|
- - if @bulk_messages.present?
- %section.list-avis.mt-8
- %h1.tab-title
- Messages envoyés précédemment
- %span.fr-badge= @bulk_messages.count
+ %p.mandatory-explanation= t('asterisk_html', scope: [:utils])
- %ul
- - @bulk_messages.each do |message|
- %li.one-avis.flex.align-start
- .width-100
- %h2.claimant
- %span.email= message.instructeur.email
- %span.date message envoyé à #{@dossiers_count} usagers le #{message.sent_at.strftime('%d/%m/%y à %H:%M')}
- %p= message.body
- .answer.flex.align-start
- - if message.piece_jointe.present?
- = render Attachment::ShowComponent.new(attachment: message.piece_jointe.attachment)
+ = render Dsfr::InputComponent.new(form: f, attribute: :body, input_type: :text_area, opts: { rows: 5, placeholder: t('views.shared.dossiers.messages.form.write_message_placeholder'), title: t('views.shared.dossiers.messages.form.write_message_placeholder'), class: 'fr-input message-textarea'})
+
+ .fr-mt-3w
+ = f.submit t('views.shared.dossiers.messages.form.send_message'), class: 'fr-btn', data: { disable: true }
- else
.page-title.center
- %h2 Il n’y a aucun dossier en brouillon dans vos groupes d’instructeurs
+ %h2 Il n’y a aucun dossier en brouillon
+
+ - if @bulk_messages.present?
+ %section.list-avis.mt-8
+ %h1.tab-title
+ Messages envoyés précédemment
+ %span.fr-badge= @bulk_messages.count
+
+ %ul
+ - @bulk_messages.each do |message|
+ %li.one-avis.flex.align-start
+ .width-100
+ %h2.claimant
+ %span.email= message.instructeur.email
+ %span.date message envoyé à #{@dossiers_count} usagers le #{message.sent_at.strftime('%d/%m/%y à %H:%M')}
+ %p= message.body
diff --git a/config/locales/models/bulk_message/en.yml b/config/locales/models/bulk_message/en.yml
new file mode 100644
index 000000000..c1a59b743
--- /dev/null
+++ b/config/locales/models/bulk_message/en.yml
@@ -0,0 +1,9 @@
+en:
+ activerecord:
+ models:
+ bulk_message:
+ one: "Bulk message to users"
+ other: "Bulk message to users"
+ attributes:
+ bulk_message:
+ body: Content
diff --git a/config/locales/models/bulk_message/fr.yml b/config/locales/models/bulk_message/fr.yml
new file mode 100644
index 000000000..04c830d1f
--- /dev/null
+++ b/config/locales/models/bulk_message/fr.yml
@@ -0,0 +1,9 @@
+fr:
+ activerecord:
+ models:
+ bulk_message:
+ one: "Message aux usagers"
+ other: "Messages aux usagers"
+ attributes:
+ bulk_message:
+ body: "Message envoyé aux destinataires :"
diff --git a/config/locales/views/instructeurs/procedures/en.yml b/config/locales/views/instructeurs/procedures/en.yml
index dab0dce11..e8d267ca7 100644
--- a/config/locales/views/instructeurs/procedures/en.yml
+++ b/config/locales/views/instructeurs/procedures/en.yml
@@ -12,8 +12,11 @@ en:
copy_link_button: Copy the procedure link to clipboard
email_usagers:
contact_users: Contact users (draft)
- notice: "You will send a message to %{dossiers_count} whose files are in draft, in the instructor groups : %{groupe_instructeurs}."
+ hint:
+ zero: "There is no user with a draft."
+ one: "You will send a message to 1 user."
+ other: "You will send a message to %{count} users."
administrators_list:
title: "%{procedure_libelle} - n°%{procedure_id} - administrators"
- stats:
+ stats:
title: Statistics
diff --git a/config/locales/views/instructeurs/procedures/fr.yml b/config/locales/views/instructeurs/procedures/fr.yml
index e2d643394..886464b85 100644
--- a/config/locales/views/instructeurs/procedures/fr.yml
+++ b/config/locales/views/instructeurs/procedures/fr.yml
@@ -12,7 +12,10 @@ fr:
copy_link_button: Copier le lien de la démarche dans le presse-papiers
email_usagers:
contact_users: Contacter les usagers (brouillon)
- notice: "Vous allez envoyer un message à %{dossiers_count} dont les dossiers sont en brouillon, dans les groupes instructeurs : %{groupe_instructeurs}."
+ hint:
+ zero: "Aucun usager n'a de dossier en brouillon."
+ one: "Vous allez envoyer un message à 1 usager ayant un dossier en brouillon."
+ other: "Vous allez envoyer un message à %{count} usagers ayant un dossier en brouillon."
administrators_list:
title: "%{procedure_libelle} - n°%{procedure_id} - administrateurs"
stats:
diff --git a/spec/controllers/instructeurs/procedures_controller_spec.rb b/spec/controllers/instructeurs/procedures_controller_spec.rb
index a6b7614f0..ee7b4c19f 100644
--- a/spec/controllers/instructeurs/procedures_controller_spec.rb
+++ b/spec/controllers/instructeurs/procedures_controller_spec.rb
@@ -486,6 +486,76 @@ describe Instructeurs::ProceduresController, type: :controller do
end
end
+ describe '#email_usagers' do
+ let(:instructeur) { create(:instructeur) }
+ let(:procedure) { create(:procedure) }
+ let!(:gi_1) { create(:groupe_instructeur, label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) }
+ let!(:dossier_without_groupe) { create(:dossier, :brouillon, procedure: procedure, groupe_instructeur: nil) }
+
+ subject do
+ get :email_usagers, params: { procedure_id: procedure.id }
+ end
+
+ it { is_expected.to redirect_to(new_user_session_path) }
+
+ context 'when authenticated' do
+ before { sign_in(instructeur.user) }
+ it 'lists dossier brouillon in groupe_instructeur as well as dossiers_brouillon outside groupe_instructeur' do
+ is_expected.to have_http_status(200)
+ expect(assigns(:dossiers_without_groupe_count)).to eq(1)
+ end
+ end
+ end
+
+ describe '#create_multiple_commentaire' do
+ let(:instructeur) { create(:instructeur) }
+ let!(:gi_p1_1) { create(:groupe_instructeur, label: '1', procedure: procedure, instructeurs: [instructeur]) }
+ let!(:gi_p1_2) { create(:groupe_instructeur, label: '2', procedure: procedure) }
+ let(:body) { "avant\napres" }
+ let(:bulk_message) { BulkMessage.first }
+ let!(:dossier) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
+ let!(:dossier_2) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
+ let!(:dossier_3) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_2) }
+ let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
+
+ before do
+ sign_in(instructeur.user)
+ procedure
+ end
+
+ let!(:dossier_4) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: nil) }
+ before do
+ post :create_multiple_commentaire,
+ params: {
+ procedure_id: procedure.id,
+ bulk_message: { body: body }
+ }
+ end
+
+ it "creates a commentaire for 1 dossiers" do
+ expect(Commentaire.count).to eq(1)
+ expect(dossier.commentaires).to eq([])
+ expect(dossier_2.commentaires).to eq([])
+ expect(dossier_3.commentaires).to eq([])
+ expect(dossier_4.commentaires.first.body).to eq("avant\napres")
+ end
+
+ it "creates a Bulk Message for 2 groupes instructeurs" do
+ expect(BulkMessage.count).to eq(1)
+ expect(bulk_message.body).to eq("avant\napres")
+ expect(bulk_message.groupe_instructeurs).to be_empty
+ end
+
+ it "creates a flash notice" do
+ expect(flash.notice).to be_present
+ expect(flash.notice).to eq("Tous les messages ont été envoyés avec succès")
+ end
+
+ it "redirect to instructeur_procedure_path" do
+ expect(response).to redirect_to instructeur_procedure_path(procedure)
+ end
+ end
+
describe '#download_export' do
let(:instructeur) { create(:instructeur) }
let!(:procedure) { create(:procedure) }
@@ -563,49 +633,4 @@ describe Instructeurs::ProceduresController, type: :controller do
it { is_expected.to have_http_status(:forbidden) }
end
end
-
- describe '#create_multiple_commentaire' do
- let(:instructeur) { create(:instructeur) }
- let!(:gi_p1_1) { create(:groupe_instructeur, label: '1', procedure: procedure) }
- let!(:gi_p1_2) { create(:groupe_instructeur, label: '2', procedure: procedure) }
- let(:body) { "avant\napres" }
- let(:bulk_message) { BulkMessage.first }
- let!(:dossier) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
- let!(:dossier_2) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
- let!(:dossier_3) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_2) }
- let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
-
- before do
- sign_in(instructeur.user)
- instructeur.groupe_instructeurs << gi_p1_1
- procedure
- post :create_multiple_commentaire,
- params: {
- procedure_id: procedure.id,
- commentaire: { body: body }
- }
- end
-
- it "creates a commentaire for 2 dossiers" do
- expect(Commentaire.count).to eq(2)
- expect(dossier.commentaires.first.body).to eq("avant\napres")
- expect(dossier_2.commentaires.first.body).to eq("avant\napres")
- expect(dossier_3.commentaires).to eq([])
- end
-
- it "creates a Bulk Message for 2 groupes instructeurs" do
- expect(BulkMessage.count).to eq(1)
- expect(bulk_message.body).to eq("avant\napres")
- expect(bulk_message.groupe_instructeurs).to match([gi_p1_1])
- end
-
- it "creates a flash notice" do
- expect(flash.notice).to be_present
- expect(flash.notice).to eq("Tous les messages ont été envoyés avec succès")
- end
-
- it "redirect to instructeur_procedure_path" do
- expect(response).to redirect_to instructeur_procedure_path(procedure)
- end
- end
end