From e78c22f33c8109ada1d5891ec7d1a3db18aa5e14 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Tue, 16 May 2023 11:21:26 +0200 Subject: [PATCH 1/8] refactor(groupe instructeur): extract method other_groupe_instructeurs --- app/models/groupe_instructeur.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/groupe_instructeur.rb b/app/models/groupe_instructeur.rb index a05a85c7c..185538b1a 100644 --- a/app/models/groupe_instructeur.rb +++ b/app/models/groupe_instructeur.rb @@ -27,9 +27,7 @@ class GroupeInstructeur < ApplicationRecord validates :label, uniqueness: { scope: :procedure } validates :closed, acceptance: { accept: [false] }, if: -> do if closed - other_groupes = procedure.groupe_instructeurs - [self] - - (other_groupes.map(&:closed) + [closed]).all? + (other_groupe_instructeurs.map(&:closed) + [closed]).all? else false end @@ -92,6 +90,10 @@ class GroupeInstructeur < ApplicationRecord !routing_rule_matches_tdc? end + def other_groupe_instructeurs + procedure.groupe_instructeurs - [self] + end + private def routing_rule_matches_tdc? From ce1429b850195eb38918435b65587003c7461ff8 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 17 May 2023 11:23:43 +0200 Subject: [PATCH 2/8] migration : add forced_group_instructeur_to_dossier --- app/models/dossier.rb | 1 + ...0230517085816_add_forced_groupe_instructeur_to_dossier.rb | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 db/migrate/20230517085816_add_forced_groupe_instructeur_to_dossier.rb diff --git a/app/models/dossier.rb b/app/models/dossier.rb index d44d9d4eb..5337e9215 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -17,6 +17,7 @@ # en_construction_close_to_expiration_notice_sent_at :datetime # en_instruction_at :datetime # for_procedure_preview :boolean default(FALSE) +# forced_groupe_instructeur :boolean # groupe_instructeur_updated_at :datetime # hidden_at :datetime # hidden_by_administration_at :datetime diff --git a/db/migrate/20230517085816_add_forced_groupe_instructeur_to_dossier.rb b/db/migrate/20230517085816_add_forced_groupe_instructeur_to_dossier.rb new file mode 100644 index 000000000..87820ee38 --- /dev/null +++ b/db/migrate/20230517085816_add_forced_groupe_instructeur_to_dossier.rb @@ -0,0 +1,5 @@ +class AddForcedGroupeInstructeurToDossier < ActiveRecord::Migration[7.0] + def change + add_column :dossiers, :forced_groupe_instructeur, :boolean, default: false, null: false + end +end From e7e702a574d05fdcc5aad141a1f77ebebf5e8aa3 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 17 May 2023 14:02:44 +0200 Subject: [PATCH 3/8] feat(routing): add reaffecter_un_dossier --- .../instructeurs/dossiers_controller.rb | 15 +++++++++++++ config/locales/fr.yml | 4 ++++ config/routes.rb | 1 + .../instructeurs/dossiers_controller_spec.rb | 21 +++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index fc4b82b19..a9fee3e01 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -331,6 +331,21 @@ module Instructeurs end end + def reaffecter_un_dossier + dossier = current_instructeur.dossiers.find(params[:dossier_id]) + + new_group = dossier + .procedure + .groupe_instructeurs.find(params[:groupe_instructeur_id]) + + dossier.assign_to_groupe_instructeur(new_group) + + dossier.update!(forced_groupe_instructeur: true) + + flash.notice = t('instructeurs.dossiers.reaffectation', dossier_id: dossier.id, label: new_group.label) + redirect_to instructeur_procedure_path(procedure) + end + private def dossier_scope diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 870ab3e23..27722f8d8 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -785,6 +785,10 @@ fr: deleted_by_instructeur: "Le dossier a bien été supprimé de votre interface" impossible_deletion: "Supression impossible : le dossier n’est pas traité" restore: "Le dossier a bien été restauré" + reaffectation: "Le dossier nº %{dossier_id} a été réaffecté au groupe d’instructeurs « %{label} »." + existing_groupe: + one: "%{count} groupe existe" + other: "%{count} groupes existent" labels: to_follow: à suivre total: dossiers diff --git a/config/routes.rb b/config/routes.rb index 4f5efd627..5a2aa080b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -450,6 +450,7 @@ Rails.application.routes.draw do post 'avis' => 'dossiers#create_avis' get 'print' => 'dossiers#print' get 'telecharger_pjs' => 'dossiers#telecharger_pjs' + post 'reaffecter_un_dossier' end end diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index 22fa39364..e43e2f383 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -1151,4 +1151,25 @@ describe Instructeurs::DossiersController, type: :controller do it { expect(flash.alert).to eq("Votre action n'a pas été effectuée, ce dossier fait parti d'un traitement de masse.") } end end + + describe '#reaffecter_un_dossier' do + let!(:gi_2) { GroupeInstructeur.create(label: 'deuxième groupe', procedure: procedure) } + let!(:dossier) { create(:dossier, :en_construction, procedure: procedure, groupe_instructeur: procedure.groupe_instructeurs.first) } + + before do + post :reaffecter, + params: { + procedure_id: procedure.id, + dossier_id: dossier.id, + groupe_instructeur_id: gi_2.id + } + end + + it do + expect(dossier.reload.groupe_instructeur.id).to eq(gi_2.id) + expect(dossier.forced_groupe_instructeur).to be_truthy + expect(response).to redirect_to(instructeur_procedure_path(procedure)) + expect(flash.notice).to eq("Le dossier nº #{dossier.id} a été réaffecté au groupe d’instructeurs « deuxième groupe ».") + end + end end From 18054fe3463c7f92f3eb6ab6ea9cd4387d2778d0 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 17 May 2023 14:49:20 +0200 Subject: [PATCH 4/8] feat(routing): add view for dossier a reaffecter --- .../instructeurs/dossiers_controller.rb | 12 +++++++++- .../dossiers/reaffectation.html.haml | 24 +++++++++++++++++++ config/routes.rb | 3 ++- .../instructeurs/dossiers_controller_spec.rb | 22 ++++++++++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 app/views/instructeurs/dossiers/reaffectation.html.haml diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index a9fee3e01..64a10cc6e 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -331,7 +331,17 @@ module Instructeurs end end - def reaffecter_un_dossier + def reaffectation + @dossier = current_instructeur.dossiers.find(params[:dossier_id]) + + @groupe_instructeur = @dossier.groupe_instructeur + + @groupes_instructeurs = Kaminari.paginate_array(@groupe_instructeur.other_groupe_instructeurs) + .page(params[:page]) + .per(ITEMS_PER_PAGE) + end + + def reaffecter dossier = current_instructeur.dossiers.find(params[:dossier_id]) new_group = dossier diff --git a/app/views/instructeurs/dossiers/reaffectation.html.haml b/app/views/instructeurs/dossiers/reaffectation.html.haml new file mode 100644 index 000000000..116191aa0 --- /dev/null +++ b/app/views/instructeurs/dossiers/reaffectation.html.haml @@ -0,0 +1,24 @@ +- content_for(:title, "Réaffectation · Dossier nº #{@dossier.id} (#{@dossier.owner_name})") + += render partial: "header", locals: { dossier: @dossier } + +.container.groupe-instructeur + + .card + .card-title Réaffectation du dossier nº #{@dossier.id} du groupe « #{@groupe_instructeur.label} » + %p + Vous pouvez réaffecter le dossier nº #{@dossier.id} à l'un des groupes d'instructeurs suivants. + %table.table.mt-2 + %thead + %tr + %th{ colspan: 2 }= t("instructeurs.dossiers.existing_groupe", count: @groupes_instructeurs.total_count) + %tbody + - @groupes_instructeurs.each do |group| + %tr + %td= group.label + %td.actions= button_to 'Réaffecter le dossier à ce groupe', + reaffecter_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, groupe_instructeur_id: group.id), + { class: 'button', + data: { confirm: "Êtes-vous sûr de vouloir réaffecter le dossier nº #{@dossier.id} du groupe « #{@groupe_instructeur.label} » vers le groupe  « #{group.label} » ?" } } + + = paginate @groupes_instructeurs, views_prefix: 'shared' diff --git a/config/routes.rb b/config/routes.rb index 5a2aa080b..ab883f5fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -450,7 +450,8 @@ Rails.application.routes.draw do post 'avis' => 'dossiers#create_avis' get 'print' => 'dossiers#print' get 'telecharger_pjs' => 'dossiers#telecharger_pjs' - post 'reaffecter_un_dossier' + get 'reaffectation' + post 'reaffecter' end end diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index e43e2f383..74eeccb38 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -1152,7 +1152,27 @@ describe Instructeurs::DossiersController, type: :controller do end end - describe '#reaffecter_un_dossier' do + describe '#reaffectation' do + let!(:gi_2) { GroupeInstructeur.create(label: 'deuxième groupe', procedure: procedure) } + let!(:gi_3) { GroupeInstructeur.create(label: 'troisième groupe', procedure: procedure) } + let!(:dossier) { create(:dossier, :en_construction, procedure: procedure, groupe_instructeur: procedure.groupe_instructeurs.first) } + + before do + post :reaffectation, + params: { + procedure_id: procedure.id, + dossier_id: dossier.id + } + end + + it do + expect(response).to have_http_status(:ok) + expect(response.body).to include("Vous pouvez réaffecter le dossier nº #{dossier.id} à l'un des groupes d'instructeurs suivants.") + expect(response.body).to include('2 groupes existent') + end + end + + describe '#reaffecter' do let!(:gi_2) { GroupeInstructeur.create(label: 'deuxième groupe', procedure: procedure) } let!(:dossier) { create(:dossier, :en_construction, procedure: procedure, groupe_instructeur: procedure.groupe_instructeurs.first) } From a9c6cc322a1560799c868bc10cf0d1b881f291bb Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Thu, 25 May 2023 16:02:47 +0200 Subject: [PATCH 5/8] feat(routing): do not run routing engine if dossier has been re routed --- app/models/routing_engine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/routing_engine.rb b/app/models/routing_engine.rb index b08cc4bf8..385acda3b 100644 --- a/app/models/routing_engine.rb +++ b/app/models/routing_engine.rb @@ -1,6 +1,7 @@ module RoutingEngine def self.compute(dossier) return if !dossier.procedure.feature_enabled?(:routing_rules) + return if dossier.forced_groupe_instructeur matching_groupe = dossier.procedure.groupe_instructeurs.active.reject(&:routing_to_configure?).find do |gi| gi.routing_rule&.compute(dossier.champs) From 3c0df601daba1a77741cacb43192914f3097c730 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Tue, 30 May 2023 17:38:59 +0200 Subject: [PATCH 6/8] feat(routing): add form in dossier page --- app/views/shared/dossiers/_demande.html.haml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/views/shared/dossiers/_demande.html.haml b/app/views/shared/dossiers/_demande.html.haml index 3cf1acd66..c87b4f940 100644 --- a/app/views/shared/dossiers/_demande.html.haml +++ b/app/views/shared/dossiers/_demande.html.haml @@ -37,3 +37,19 @@ - if champs.any? || dossier.procedure.routing_enabled? .card = render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile } + + - if dossier.procedure.routing_enabled? + %h2.fr-h6 + Réaffectation + .card + En cas d'erreur de l'usager, vous pouvez réaffecter le dossier vers l'un des groupes d'instructeurs suivants + = form_tag reaffecter_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id), + method: :post, + class: 'fr-mb-3w mt-2' do + .flex + = select_tag(:groupe_instructeur_id, + options_for_select(@dossier.groupe_instructeur.other_groupe_instructeurs.pluck(:label, :id)), + include_blank: true, + class: 'fr-select flex auto fr-mr-2w') + + = button_tag 'Réaffecter', class: 'fr-btn fr-btn--secondary' From 35d28610aaf7db32a3ee731690ad2848281c99fc Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 14 Jun 2023 12:30:02 +0200 Subject: [PATCH 7/8] move reaffectation view in a dynamic tab item --- app/views/instructeurs/dossiers/_header_bottom.html.haml | 3 +++ config/locales/en.yml | 1 + config/locales/fr.yml | 1 + 3 files changed, 5 insertions(+) diff --git a/app/views/instructeurs/dossiers/_header_bottom.html.haml b/app/views/instructeurs/dossiers/_header_bottom.html.haml index 793ae4c8f..cb194f149 100644 --- a/app/views/instructeurs/dossiers/_header_bottom.html.haml +++ b/app/views/instructeurs/dossiers/_header_bottom.html.haml @@ -22,3 +22,6 @@ = dynamic_tab_item(t('views.instructeurs.dossiers.tab_steps.involved_persons'), personnes_impliquees_instructeur_dossier_path(dossier.procedure, dossier)) + + = dynamic_tab_item(t('views.instructeurs.dossiers.tab_steps.reaffectation'), + reaffectation_instructeur_dossier_path(dossier.procedure, dossier)) diff --git a/config/locales/en.yml b/config/locales/en.yml index 85a1e8d80..875e6851e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -355,6 +355,7 @@ en: external_opinion: External opinion messaging: Messaging involved_persons: Involved persons + reaffectation: reassignment tab_explainations: a_suivre: No instructor is assigned to follow up on these files. Be the first ! suivis: The folders that are in this tab are only those that you follow. You can exchange with the requester until you can accept them, refuse them or classify them without follow-up. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 27722f8d8..7a2ea3416 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -355,6 +355,7 @@ fr: external_opinion: Avis externes messaging: Messagerie involved_persons: Personnes impliquées + reaffectation: Réaffectation tab_explainations: a_suivre: Aucun instructeur n’est affecté au suivi de ces dossiers. Soyez le premier ! suivis: Les dossiers qui sont dans cet onglet sont uniquement ceux que vous suivez. Vous pouvez échanger avec le demandeur jusqu’à pouvoir les accepter, les refuser ou les classer sans suite. From 98cdc63d5c36058cf17285c39d7bce97816502b1 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 14 Jun 2023 12:35:43 +0200 Subject: [PATCH 8/8] add rerouting feature flag --- app/views/instructeurs/dossiers/_header_bottom.html.haml | 5 +++-- config/initializers/flipper.rb | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/instructeurs/dossiers/_header_bottom.html.haml b/app/views/instructeurs/dossiers/_header_bottom.html.haml index cb194f149..17d192f9d 100644 --- a/app/views/instructeurs/dossiers/_header_bottom.html.haml +++ b/app/views/instructeurs/dossiers/_header_bottom.html.haml @@ -23,5 +23,6 @@ = dynamic_tab_item(t('views.instructeurs.dossiers.tab_steps.involved_persons'), personnes_impliquees_instructeur_dossier_path(dossier.procedure, dossier)) - = dynamic_tab_item(t('views.instructeurs.dossiers.tab_steps.reaffectation'), - reaffectation_instructeur_dossier_path(dossier.procedure, dossier)) + - if dossier.procedure.routing_enabled? && dossier.procedure.feature_enabled?(:rerouting) + = dynamic_tab_item(t('views.instructeurs.dossiers.tab_steps.reaffectation'), + reaffectation_instructeur_dossier_path(dossier.procedure, dossier)) diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb index 37de69a0a..3df08aafe 100644 --- a/config/initializers/flipper.rb +++ b/config/initializers/flipper.rb @@ -18,7 +18,8 @@ features = [ :hide_instructeur_email, :procedure_routage_api, :routing_rules, - :groupe_instructeur_api_hack + :groupe_instructeur_api_hack, + :rerouting ] def database_exists?