Merge pull request #8940 from demarches-simplifiees/routing-new-ux
Nouvelle UX pour le routage
This commit is contained in:
commit
bbedf0e659
59 changed files with 917 additions and 714 deletions
|
@ -42,6 +42,10 @@
|
||||||
&.row-reverse {
|
&.row-reverse {
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.auto {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
|
|
|
@ -2,10 +2,11 @@ class Dsfr::SidemenuComponent < ApplicationComponent
|
||||||
renders_many :links, "LinkComponent"
|
renders_many :links, "LinkComponent"
|
||||||
|
|
||||||
class LinkComponent < ApplicationComponent
|
class LinkComponent < ApplicationComponent
|
||||||
attr_reader :name, :url
|
attr_reader :name, :url, :icon
|
||||||
def initialize(name:, url:)
|
def initialize(name:, url:, icon: nil)
|
||||||
@name = name
|
@name = name
|
||||||
@url = url
|
@url = url
|
||||||
|
@icon = icon
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,8 @@
|
||||||
%ul.fr-sidemenu__list
|
%ul.fr-sidemenu__list
|
||||||
- links.each do |link|
|
- links.each do |link|
|
||||||
%li{ class: "fr-sidemenu__item fr-sidemenu__item#{active?(link.url) ? '--active' : ''}" }
|
%li{ class: "fr-sidemenu__item fr-sidemenu__item#{active?(link.url) ? '--active' : ''}" }
|
||||||
= link_to link.name, link.url, class: 'fr-sidemenu__link', 'aria-current': active?(link.url) ? 'page' : nil, target: "_self"
|
= link_to link.url, class: 'fr-sidemenu__link ', 'aria-current': active?(link.url) ? 'page' : nil, target: "_self" do
|
||||||
|
- capture do
|
||||||
|
- if link.icon.present?
|
||||||
|
%span{ class: link.icon }
|
||||||
|
= link.name
|
||||||
|
|
6
app/components/procedure/groupes_ajout_component.rb
Normal file
6
app/components/procedure/groupes_ajout_component.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class Procedure::GroupesAjoutComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:, groupe_instructeurs:)
|
||||||
|
@procedure = procedure
|
||||||
|
@groupe_instructeurs = groupe_instructeurs
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
add_a_group:
|
||||||
|
title: Nouveau groupe
|
||||||
|
button:
|
||||||
|
add_group: Ajouter
|
|
@ -0,0 +1,15 @@
|
||||||
|
- content_for(:title, 'Ajout de groupes')
|
||||||
|
%h1 Ajout de groupes d'instructeurs
|
||||||
|
|
||||||
|
= render partial: 'administrateurs/groupe_instructeurs/import_export',
|
||||||
|
locals: { procedure: @procedure,
|
||||||
|
groupe_instructeurs: @groupe_instructeurs }
|
||||||
|
|
||||||
|
%section
|
||||||
|
= form_for :groupe_instructeur,
|
||||||
|
method: :post do |f|
|
||||||
|
= f.label :label, class: 'fr-label fr-mb-1w' do
|
||||||
|
= t('.add_a_group.title')
|
||||||
|
.flex.justify-between.align-baseline.fr-mb-1w
|
||||||
|
= f.text_field :label, required: true, class: 'fr-input', placeholder: 'Entrer un nom de groupe'
|
||||||
|
= f.button t('.button.add_group'), class: "fr-btn fr-btn fr-btn--secondary fr-btn--icon-right fr-icon-add-line ml-2"
|
26
app/components/procedure/groupes_management_component.rb
Normal file
26
app/components/procedure/groupes_management_component.rb
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Procedure::GroupesManagementComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:, groupe_instructeurs:, query:)
|
||||||
|
@procedure = procedure
|
||||||
|
@groupe_instructeurs = groupe_instructeurs
|
||||||
|
@query = query
|
||||||
|
@total = groupe_instructeurs.total_count
|
||||||
|
end
|
||||||
|
|
||||||
|
def table_header
|
||||||
|
if @query.present?
|
||||||
|
if @groupe_instructeurs.length != @total
|
||||||
|
"#{t('.groupe', count: @groupe_instructeurs.length)} sur #{@total} #{t('.found', count: @total)}"
|
||||||
|
else
|
||||||
|
"#{t('.groupe', count: @groupe_instructeurs.length)} #{t('.found', count: @groupe_instructeurs.length)}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if @groupe_instructeurs.length != @total
|
||||||
|
"#{t('.groupe', count: @groupe_instructeurs.length)} sur #{@total}"
|
||||||
|
else
|
||||||
|
t('.groupe', count: @groupe_instructeurs.length)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
groupe:
|
||||||
|
one: "%{count} groupe"
|
||||||
|
other: "%{count} groupes"
|
||||||
|
found:
|
||||||
|
one: "trouvé"
|
||||||
|
other: "trouvés"
|
|
@ -0,0 +1,40 @@
|
||||||
|
- content_for(:title, 'Groupes')
|
||||||
|
%h1 Gestion des groupes
|
||||||
|
|
||||||
|
= render Procedure::GroupesSearchComponent.new(procedure: @procedure, query: @query, to_configure_count: @procedure.groupe_instructeurs.filter(&:routing_to_configure?).count)
|
||||||
|
|
||||||
|
.fr-table.fr-table--no-caption.fr-table--layout-fixed.fr-mt-2w
|
||||||
|
%table
|
||||||
|
%caption= table_header
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th{ scope: "col" }
|
||||||
|
.flex
|
||||||
|
.flex.auto= table_header
|
||||||
|
%span.fr-icon.fr-icon-user-line
|
||||||
|
%tbody
|
||||||
|
- @groupe_instructeurs.each do |gi|
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
.flex
|
||||||
|
.flex.auto
|
||||||
|
= link_to admin_procedure_groupe_instructeur_path(@procedure, gi), class: 'fr-link' do
|
||||||
|
%span= gi.label
|
||||||
|
- if gi.closed
|
||||||
|
%p.fr-badge.fr-badge--info.fr-badge--sm.fr-ml-1w inactif
|
||||||
|
- elsif gi.routing_to_configure?
|
||||||
|
%p.fr-badge.fr-badge--warning.fr-badge--sm.fr-ml-1w à configurer
|
||||||
|
|
||||||
|
%div{ style: 'width: 25px; text-align: center;' }
|
||||||
|
#{gi.instructeurs.count}
|
||||||
|
%p= gi.routing_rule&.to_s(@procedure.active_revision.types_de_champ)
|
||||||
|
.fr-mt-1w
|
||||||
|
= paginate @groupe_instructeurs
|
||||||
|
|
||||||
|
= form_tag admin_procedure_update_defaut_groupe_instructeur_path,
|
||||||
|
class: 'fr-my-3w',
|
||||||
|
data: { controller: 'autosave' } do
|
||||||
|
= label_tag :defaut_groupe_instructeur_id, 'Et si aucune règle ne correspond, router vers :', class: 'fr-label'
|
||||||
|
= select_tag :defaut_groupe_instructeur_id,
|
||||||
|
options_for_select(@procedure.groupe_instructeurs.pluck(:label, :id), selected: @procedure.defaut_groupe_instructeur.id),
|
||||||
|
class: 'fr-select'
|
5
app/components/procedure/groupes_search_component.rb
Normal file
5
app/components/procedure/groupes_search_component.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class Procedure::GroupesSearchComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:, query:, to_configure_count:)
|
||||||
|
@procedure, @query, @to_configure_count = procedure, query, to_configure_count
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
= form_for admin_procedure_groupe_instructeurs_path(@procedure),
|
||||||
|
method: :get do
|
||||||
|
#header-search.fr-search-bar.fr-mb-2w{ role: "search" }
|
||||||
|
= label_tag :q, 'Rechercher par nom', class: 'fr-label'
|
||||||
|
= text_field_tag :q, @query, class: 'fr-input', type: 'search', autocomplete: 'off', placeholder: 'Rechercher par nom'
|
||||||
|
%button.fr-btn{ title: "Rechercher" } Rechercher
|
||||||
|
|
||||||
|
- if @to_configure_count > 0
|
||||||
|
%span #{ @to_configure_count } à configurer
|
|
@ -0,0 +1,9 @@
|
||||||
|
class Procedure::InstructeursManagementComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:, groupe_instructeur:, instructeurs:, available_instructeur_emails:, disabled_as_super_admin:)
|
||||||
|
@procedure = procedure
|
||||||
|
@groupe_instructeur = groupe_instructeur
|
||||||
|
@instructeurs = instructeurs
|
||||||
|
@available_instructeur_emails = available_instructeur_emails
|
||||||
|
@disabled_as_super_admin = disabled_as_super_admin
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
- content_for(:title, 'Instructeurs')
|
||||||
|
%h1 Gestion des instructeurs
|
||||||
|
|
||||||
|
= render partial: 'administrateurs/groupe_instructeurs/import_export',
|
||||||
|
locals: { procedure: @procedure,
|
||||||
|
groupe_instructeurs: @procedure.groupe_instructeurs }
|
||||||
|
|
||||||
|
= render partial: 'administrateurs/groupe_instructeurs/instructeurs',
|
||||||
|
locals: { procedure: @procedure,
|
||||||
|
groupe_instructeur: @groupe_instructeur,
|
||||||
|
instructeurs: @instructeurs,
|
||||||
|
available_instructeur_emails: @available_instructeur_emails,
|
||||||
|
disabled_as_super_admin: @disabled_as_super_admin }
|
22
app/components/procedure/instructeurs_menu_component.rb
Normal file
22
app/components/procedure/instructeurs_menu_component.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class Procedure::InstructeursMenuComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:)
|
||||||
|
@procedure = procedure
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def links
|
||||||
|
first_option, first_icon = if @procedure.groupe_instructeurs.one?
|
||||||
|
instructeurs_count = @procedure.groupe_instructeurs.first.instructeurs.count
|
||||||
|
[t('.instructeurs', count: instructeurs_count), 'fr-icon-user-line']
|
||||||
|
else
|
||||||
|
["#{@procedure.groupe_instructeurs.count} groupes", 'fr-icon-group-line']
|
||||||
|
end
|
||||||
|
|
||||||
|
[
|
||||||
|
{ name: first_option, url: admin_procedure_groupe_instructeurs_path(@procedure), icon: "#{first_icon} fr-icon--sm" },
|
||||||
|
({ name: 'Ajout de groupes', url: ajout_admin_procedure_groupe_instructeurs_path(@procedure), icon: 'fr-icon-add-circle-line fr-icon--sm' } if @procedure.routing_enabled?),
|
||||||
|
{ name: 'Options', url: options_admin_procedure_groupe_instructeurs_path(@procedure), icon: 'fr-icon-settings-5-line fr-icon--sm' }
|
||||||
|
].compact
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
instructeurs:
|
||||||
|
one: "%{count} instructeur"
|
||||||
|
other: "%{count} instructeurs"
|
|
@ -0,0 +1,7 @@
|
||||||
|
.container
|
||||||
|
.fr-grid-row
|
||||||
|
.fr-col.fr-col-12.fr-col-md-3
|
||||||
|
= render(Dsfr::SidemenuComponent.new) do |component|
|
||||||
|
- component.with_links(links)
|
||||||
|
.fr-col= content
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
class Procedure::InstructeursOptionsComponent < ApplicationComponent
|
||||||
|
def initialize(procedure:, state:)
|
||||||
|
@procedure = procedure
|
||||||
|
@state = state
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
routing_configuration_notice_1:
|
||||||
|
Le routage permet d’acheminer les dossiers vers différents groupes d’instructeurs.
|
||||||
|
routing_configuration_notice_2_html: |
|
||||||
|
<p>Pour le configurer, votre formulaire doit comporter
|
||||||
|
au moins un champ « choix simple ».</p>
|
||||||
|
<p>Ajoutez ce champ dans la page <a href="%{path}">« Configuration des champs »</a>.</p>
|
||||||
|
delete_title: Aucun dossier ne sera supprimé. Les groupes d'instructeurs vont être supprimés. Seuls les instructeurs du groupe « %{defaut_label} » resteront affectés à la procédure.
|
||||||
|
delete_confirmation: |
|
||||||
|
Attention : tous les dossiers vont être déplacés dans le groupe « %{defaut_label} » et seuls les instructeurs présent dans ce groupe resteront affectés à la procédure. Souhaitez-vous continuer ?
|
|
@ -0,0 +1,49 @@
|
||||||
|
- content_for(:title, 'Options')
|
||||||
|
- if @state.nil?
|
||||||
|
%h1 Options concernant l’instruction
|
||||||
|
|
||||||
|
%ul.fr-toggle__list
|
||||||
|
%li
|
||||||
|
= form_for @procedure,
|
||||||
|
method: :patch,
|
||||||
|
url: update_instructeurs_self_management_enabled_admin_procedure_groupe_instructeurs_path(@procedure),
|
||||||
|
data: { controller: 'autosubmit', turbo: 'true' } do |f|
|
||||||
|
|
||||||
|
= render Dsfr::ToggleComponent.new(form: f,
|
||||||
|
target: :instructeurs_self_management_enabled,
|
||||||
|
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.#{ ' Lorsque la démarche est routée, l’autogestion est activée d’office et n’est pas désactivable.' if @procedure.routing_enabled? }",
|
||||||
|
disabled: @procedure.routing_enabled?)
|
||||||
|
%p.fr-mt-2w Routage
|
||||||
|
%p.fr-mt-2w= t('.routing_configuration_notice_1')
|
||||||
|
- if @procedure.active_revision.routable_types_de_champ.none?
|
||||||
|
%p.fr-mt-2w= t('.routing_configuration_notice_2_html', path: champs_admin_procedure_path(@procedure))
|
||||||
|
- elsif @procedure.groupe_instructeurs.active.one?
|
||||||
|
= link_to 'Configurer le routage', options_admin_procedure_groupe_instructeurs_path(@procedure, state: :choix), class: 'fr-btn'
|
||||||
|
|
||||||
|
- else
|
||||||
|
= button_to 'Supprimer le routage',
|
||||||
|
destroy_all_groups_but_defaut_admin_procedure_groupe_instructeurs_path,
|
||||||
|
class: 'fr-btn',
|
||||||
|
method: :delete,
|
||||||
|
title: t('.delete_title', defaut_label: @procedure.defaut_groupe_instructeur.label),
|
||||||
|
data: ( @procedure.publiee? ? { disable_with: "Suppression...", confirm: t('.delete_confirmation', defaut_label: @procedure.defaut_groupe_instructeur.label) } : nil)
|
||||||
|
|
||||||
|
- elsif @state == 'choix'
|
||||||
|
= form_for :choice,
|
||||||
|
method: :patch,
|
||||||
|
data: { controller: 'radio-enabled-submit' },
|
||||||
|
url: wizard_admin_procedure_groupe_instructeurs_path(@procedure) do |f|
|
||||||
|
|
||||||
|
%div{ data: { 'action': "click->radio-enabled-submit#click" } }
|
||||||
|
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||||
|
target: :state,
|
||||||
|
buttons: [ { label: 'À partir d’un champ', value: 'routage_simple', hint: 'crée les groupes en fonction d’un champ du formulaire' } ,
|
||||||
|
{ label: 'Avancé', value: 'routage_custom', hint: 'libre à vous de créer et de configurer les groupes' }]) do
|
||||||
|
%h1 Choix du type de routage
|
||||||
|
|
||||||
|
%ul.fr-btns-group.fr-btns-group--inline-sm
|
||||||
|
%li
|
||||||
|
= link_to 'Retour', options_admin_procedure_groupe_instructeurs_path(@procedure), class: 'fr-btn fr-btn--secondary'
|
||||||
|
%li
|
||||||
|
%button.fr-btn{ disabled: true, data: { 'radio-enabled-submit-target': 'submit' } } Continuer
|
65
app/components/procedure/one_groupe_management_component.rb
Normal file
65
app/components/procedure/one_groupe_management_component.rb
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
class Procedure::OneGroupeManagementComponent < ApplicationComponent
|
||||||
|
include Logic
|
||||||
|
|
||||||
|
def initialize(revision:, groupe_instructeur:)
|
||||||
|
@revision = revision
|
||||||
|
@groupe_instructeur = groupe_instructeur
|
||||||
|
@procedure_id = revision.procedure_id
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def targeted_champ
|
||||||
|
@groupe_instructeur.routing_rule&.left || empty
|
||||||
|
end
|
||||||
|
|
||||||
|
def value
|
||||||
|
@groupe_instructeur.routing_rule&.right || empty
|
||||||
|
end
|
||||||
|
|
||||||
|
def targeted_champ_tag
|
||||||
|
select_tag(
|
||||||
|
'targeted_champ',
|
||||||
|
options_for_select(targeted_champs_for_select, selected: targeted_champ.to_json),
|
||||||
|
class: 'fr-select'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def targeted_champs_for_select
|
||||||
|
empty_target_for_select + available_targets_for_select
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty_target_for_select
|
||||||
|
[[t('.select'), empty.to_json]]
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_targets_for_select
|
||||||
|
@revision
|
||||||
|
.routable_types_de_champ
|
||||||
|
.map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def value_tag
|
||||||
|
select_tag(
|
||||||
|
'value',
|
||||||
|
options_for_select(
|
||||||
|
values_for_select(targeted_champ),
|
||||||
|
selected: value.to_json
|
||||||
|
),
|
||||||
|
class: 'fr-select'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def values_for_select(targeted_champ)
|
||||||
|
(empty_target_for_select + available_values_for_select(targeted_champ))
|
||||||
|
# add id to help morph render selected option
|
||||||
|
.map { |(libelle, json)| [libelle, json, { id: "option-#{libelle}" }] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_values_for_select(targeted_champ)
|
||||||
|
return [] if targeted_champ.is_a?(Logic::Empty)
|
||||||
|
targeted_champ
|
||||||
|
.options(@revision.types_de_champ_public)
|
||||||
|
.map { |tdc| [tdc.first, constant(tdc.first).to_json] }
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
select: Sélectionner
|
||||||
|
move_files_confirmation: Réaffecter les dossiers à un autre groupe afin de pouvoir le supprimer
|
||||||
|
move_files:
|
||||||
|
zero: Déplacer les dossiers en brouillon
|
||||||
|
one: Déplacer un dossier
|
||||||
|
other: Déplacer les %{count} dossiers
|
|
@ -0,0 +1,55 @@
|
||||||
|
%div{ id: dom_id(@groupe_instructeur, :routing) }
|
||||||
|
%h2 Paramètres principaux
|
||||||
|
|
||||||
|
= form_for @groupe_instructeur,
|
||||||
|
url: admin_procedure_groupe_instructeur_path(@procedure_id, @groupe_instructeur),
|
||||||
|
method: :patch do |f|
|
||||||
|
= f.label :label, 'Nom du groupe', class: 'fr-label fr-mb-1w'
|
||||||
|
.flex
|
||||||
|
= f.text_field :label, required: true, class: 'fr-input flex auto fr-mr-2w'
|
||||||
|
= f.button 'Renommer', class: 'fr-btn fr-btn--secondary'
|
||||||
|
|
||||||
|
= form_for @groupe_instructeur,
|
||||||
|
url: admin_procedure_groupe_instructeur_update_state_path(@procedure_id, @groupe_instructeur),
|
||||||
|
method: :patch,
|
||||||
|
data: { turbo: true, controller: 'autosubmit' } do |f|
|
||||||
|
.fr-checkbox-group.fr-my-3w
|
||||||
|
= f.check_box :closed, { id: 'closed', "aria-describedby" => "closed-messages", :name => "closed" }
|
||||||
|
%label.fr-label{ :for => "closed" }
|
||||||
|
Groupe inactif
|
||||||
|
%span.fr-hint-text Si cette option est activée, les usagers ne pourront plus sélectionner ce groupe d'instructeurs
|
||||||
|
|
||||||
|
= form_tag admin_procedure_routing_rules_path(@procedure_id),
|
||||||
|
method: :post,
|
||||||
|
data: { controller: 'autosave' },
|
||||||
|
class: 'fr-mb-3w' do
|
||||||
|
|
||||||
|
= hidden_field_tag('groupe_instructeur_id', @groupe_instructeur.id)
|
||||||
|
|
||||||
|
.flex
|
||||||
|
%p.fr-mb-1w.fr-mr-2w Routage
|
||||||
|
- if @groupe_instructeur.routing_to_configure?
|
||||||
|
%p.fr-mb-1w.fr-badge.fr-badge--warning.fr-badge--sm à configurer
|
||||||
|
|
||||||
|
.flex.align-baseline
|
||||||
|
.fr-mr-2w si le champ
|
||||||
|
.target.fr-mr-2w
|
||||||
|
= targeted_champ_tag
|
||||||
|
.operator.fr-mr-2w est égal à
|
||||||
|
.value
|
||||||
|
= value_tag
|
||||||
|
|
||||||
|
%ul.fr-btns-group.fr-btns-group--sm.fr-btns-group--inline.fr-btns-group--icon-right
|
||||||
|
%li
|
||||||
|
- if @groupe_instructeur.can_delete?
|
||||||
|
%p Supprimer le groupe
|
||||||
|
= button_to admin_procedure_groupe_instructeur_path(@procedure_id, @groupe_instructeur),
|
||||||
|
class: 'fr-btn fr-btn--tertiary fr-btn--icon-left fr-icon-delete-line',
|
||||||
|
method: :delete do
|
||||||
|
Supprimer
|
||||||
|
- else
|
||||||
|
= button_to reaffecter_dossiers_admin_procedure_groupe_instructeur_path(@procedure_id, @groupe_instructeur),
|
||||||
|
class: 'fr-btn fr-btn--tertiary fr-icon-folder-2-line',
|
||||||
|
title: t('.move_files_confirmation'),
|
||||||
|
method: :get do
|
||||||
|
= t('.move_files', count: @groupe_instructeur.dossiers.visible_by_administration.size)
|
|
@ -24,6 +24,7 @@ fr:
|
||||||
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} ».
|
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} ».
|
||||||
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié.
|
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié.
|
||||||
update_drop_down_options: "Les options de sélection du champ « %{label} » ont été modifiées :"
|
update_drop_down_options: "Les options de sélection du champ « %{label} » ont été modifiées :"
|
||||||
|
update_drop_down_options_alert: "Le champ « %{label} » est utilisé pour le routage des dossiers. Veuillez mettre à jour la configuration des groupes d'instructeurs après avoir publié les modifications."
|
||||||
enable_mandatory: Le champ « %{label} » est maintenant obligatoire.
|
enable_mandatory: Le champ « %{label} » est maintenant obligatoire.
|
||||||
disable_mandatory: Le champ « %{label} » n’est plus obligatoire.
|
disable_mandatory: Le champ « %{label} » n’est plus obligatoire.
|
||||||
enable_drop_down_other: Le champ « %{label} » comporte maintenant un choix « Autre ».
|
enable_drop_down_other: Le champ « %{label} » comporte maintenant un choix « Autre ».
|
||||||
|
|
|
@ -74,6 +74,9 @@
|
||||||
- if !total_dossiers.zero? && !change.can_rebase?
|
- if !total_dossiers.zero? && !change.can_rebase?
|
||||||
.fr-alert.fr-alert--warning.fr-mt-1v
|
.fr-alert.fr-alert--warning.fr-mt-1v
|
||||||
%p= t('.breaking_change', count: total_dossiers)
|
%p= t('.breaking_change', count: total_dossiers)
|
||||||
|
- if removed.present? && change.type_de_champ.used_by_routing_rules?
|
||||||
|
.fr-alert.fr-alert--warning.fr-mt-1v
|
||||||
|
= t(".#{prefix}.update_drop_down_options_alert", label: change.label)
|
||||||
- when :drop_down_other
|
- when :drop_down_other
|
||||||
- if change.from == false
|
- if change.from == false
|
||||||
- list.with_item do
|
- list.with_item do
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
class Procedure::RoutingRulesComponent < ApplicationComponent
|
|
||||||
include Logic
|
|
||||||
|
|
||||||
def initialize(revision:, groupe_instructeurs:)
|
|
||||||
@revision = revision
|
|
||||||
@groupe_instructeurs = groupe_instructeurs
|
|
||||||
@procedure_id = revision.procedure_id
|
|
||||||
end
|
|
||||||
|
|
||||||
def rows
|
|
||||||
@groupe_instructeurs.active.map do |gi|
|
|
||||||
if gi.routing_rule.present?
|
|
||||||
[gi.routing_rule.left, gi.routing_rule.right, gi]
|
|
||||||
else
|
|
||||||
[empty, empty, gi]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def can_route?
|
|
||||||
available_targets_for_select.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def targeted_champ_tag(targeted_champ, row_index)
|
|
||||||
select_tag(
|
|
||||||
'targeted_champ',
|
|
||||||
options_for_select(targeted_champs_for_select, selected: targeted_champ.to_json),
|
|
||||||
id: input_id_for('targeted_champ', row_index)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def value_tag(targeted_champ, value, row_index)
|
|
||||||
select_tag(
|
|
||||||
'value',
|
|
||||||
options_for_select(
|
|
||||||
values_for_select(targeted_champ, row_index),
|
|
||||||
selected: value.to_json
|
|
||||||
),
|
|
||||||
id: input_id_for('value', row_index)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def hidden_groupe_instructeur_tag(groupe_instructeur_id)
|
|
||||||
hidden_field_tag(
|
|
||||||
'groupe_instructeur_id',
|
|
||||||
groupe_instructeur_id
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def targeted_champs_for_select
|
|
||||||
empty_target_for_select + available_targets_for_select
|
|
||||||
end
|
|
||||||
|
|
||||||
def empty_target_for_select
|
|
||||||
[[t('.select'), empty.to_json]]
|
|
||||||
end
|
|
||||||
|
|
||||||
def available_targets_for_select
|
|
||||||
@revision.types_de_champ_public
|
|
||||||
.filter { |tdc| [:drop_down_list].include?(tdc.type_champ.to_sym) }
|
|
||||||
.map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def available_values_for_select(targeted_champ)
|
|
||||||
return [] if targeted_champ.is_a?(Logic::Empty)
|
|
||||||
targeted_champ
|
|
||||||
.options(@revision.types_de_champ_public)
|
|
||||||
.map { |tdc| [tdc.first, constant(tdc.first).to_json] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def values_for_select(targeted_champ, row_index)
|
|
||||||
(empty_target_for_select + available_values_for_select(targeted_champ))
|
|
||||||
# add id to help morph render selected option
|
|
||||||
.map { |(libelle, json)| [libelle, json, { id: "#{row_index}-option-#{libelle}" }] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def input_id_for(name, row_index)
|
|
||||||
"#{name}-#{row_index}"
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
fr:
|
|
||||||
select: Sélectionner
|
|
||||||
apply_routing_rules: Règles de routage
|
|
||||||
routing_rules_notice_html: |
|
|
||||||
<p>Ajoutez des règles de routage à partir de champs « choix simple » créés dans le <a href="%{path}">formulaire</a>.</p>
|
|
||||||
<p>Les dossiers seront routées vers le premier groupe affiché dont la règle correspond.</p>
|
|
||||||
routing_rules_warning_html: |
|
|
||||||
<p>Pour appliquer des règles de routage, votre formulaire doit comporter
|
|
||||||
au moins un champ « choix simple ».</p>
|
|
||||||
<p>Ajoutez ce champ dans la page <a href="%{path}">« Configuration des champs »</a>.</p>
|
|
|
@ -1,40 +0,0 @@
|
||||||
.card#routing-rules
|
|
||||||
%h2.card-title= t('.apply_routing_rules')
|
|
||||||
- if can_route?
|
|
||||||
.notice
|
|
||||||
= t('.routing_rules_notice_html', path: champs_admin_procedure_path(@procedure_id))
|
|
||||||
.mt-2.width-100
|
|
||||||
%table.routing-rules-table.mt-2.width-100
|
|
||||||
%thead
|
|
||||||
%tr
|
|
||||||
%th.far-left Router vers
|
|
||||||
%th.if
|
|
||||||
%th.target Champ cible du routage
|
|
||||||
%th.operator
|
|
||||||
%th.value Valeur
|
|
||||||
.mt-2.width-100
|
|
||||||
- rows.each.with_index do |(targeted_champ, value, groupe_instructeur), row_index|
|
|
||||||
= form_tag admin_procedure_routing_rules_path(@procedure_id),
|
|
||||||
method: :post,
|
|
||||||
class: "form width-100 gi-#{groupe_instructeur.id}",
|
|
||||||
data: { controller: 'autosave' } do
|
|
||||||
= hidden_groupe_instructeur_tag(groupe_instructeur.id)
|
|
||||||
%table.routing-rules-table.condition-table.mt-2.width-100
|
|
||||||
%tbody
|
|
||||||
%tr
|
|
||||||
%td.far-left= groupe_instructeur.label
|
|
||||||
%td.if si
|
|
||||||
%td.target= targeted_champ_tag(targeted_champ, row_index)
|
|
||||||
%td.operator est égal à
|
|
||||||
%td.value= value_tag(targeted_champ, value, row_index)
|
|
||||||
|
|
||||||
= form_tag admin_procedure_update_defaut_groupe_instructeur_path(@procedure_id),
|
|
||||||
class: 'form flex align-baseline defaut-groupe',
|
|
||||||
data: { controller: 'autosave' } do
|
|
||||||
= label_tag :defaut_groupe_instructeur_id, 'Et si aucune règle ne correspond, router vers :'
|
|
||||||
= select_tag :defaut_groupe_instructeur_id,
|
|
||||||
options_for_select(@groupe_instructeurs.pluck(:label, :id), selected: @revision.procedure.defaut_groupe_instructeur.id),
|
|
||||||
class: 'width-100'
|
|
||||||
|
|
||||||
- else
|
|
||||||
.notice= t('.routing_rules_warning_html', path: champs_admin_procedure_path(@procedure_id))
|
|
|
@ -1,6 +1,7 @@
|
||||||
module Administrateurs
|
module Administrateurs
|
||||||
class GroupeInstructeursController < AdministrateurController
|
class GroupeInstructeursController < AdministrateurController
|
||||||
include ActiveSupport::NumberHelper
|
include ActiveSupport::NumberHelper
|
||||||
|
include Logic
|
||||||
|
|
||||||
before_action :ensure_not_super_admin!, only: [:add_instructeur]
|
before_action :ensure_not_super_admin!, only: [:add_instructeur]
|
||||||
|
|
||||||
|
@ -19,6 +20,73 @@ module Administrateurs
|
||||||
@available_instructeur_emails = available_instructeur_emails
|
@available_instructeur_emails = available_instructeur_emails
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
@procedure = procedure
|
||||||
|
end
|
||||||
|
|
||||||
|
def ajout
|
||||||
|
redirect_to admin_procedure_groupe_instructeurs_path(procedure) if procedure.groupe_instructeurs.one?
|
||||||
|
@procedure = procedure
|
||||||
|
@groupes_instructeurs = paginated_groupe_instructeurs
|
||||||
|
end
|
||||||
|
|
||||||
|
def simple_routing
|
||||||
|
@procedure = procedure
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_simple_routing
|
||||||
|
@procedure = procedure
|
||||||
|
stable_id = params[:create_simple_routing][:stable_id].to_i
|
||||||
|
|
||||||
|
tdc = @procedure.active_revision.routable_types_de_champ.find { |tdc| tdc.stable_id == stable_id }
|
||||||
|
|
||||||
|
tdc_options = tdc.options["drop_down_options"].reject(&:empty?)
|
||||||
|
|
||||||
|
tdc_options.each do |option_label|
|
||||||
|
gi = procedure.groupe_instructeurs.find_by({ label: option_label }) || procedure.groupe_instructeurs
|
||||||
|
.create({ label: option_label, instructeurs: [current_administrateur.instructeur] })
|
||||||
|
gi.update(routing_rule: ds_eq(champ_value(stable_id), constant(gi.label)))
|
||||||
|
end
|
||||||
|
|
||||||
|
defaut = @procedure.defaut_groupe_instructeur
|
||||||
|
|
||||||
|
if !tdc_options.include?(defaut.label)
|
||||||
|
new_defaut = @procedure.reload.groupe_instructeurs_but_defaut.first
|
||||||
|
@procedure.update!(defaut_groupe_instructeur: new_defaut)
|
||||||
|
reaffecter_all_dossiers_to_defaut_groupe
|
||||||
|
defaut.instructeurs.each { new_defaut.add(_1) }
|
||||||
|
defaut.destroy!
|
||||||
|
end
|
||||||
|
|
||||||
|
flash.notice = 'Les groupes instructeurs ont été ajoutés'
|
||||||
|
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wizard
|
||||||
|
if params[:choice][:state] == 'routage_custom'
|
||||||
|
new_label = procedure.defaut_groupe_instructeur.label + ' bis'
|
||||||
|
procedure.groupe_instructeurs
|
||||||
|
.create({ label: new_label, instructeurs: [current_administrateur.instructeur] })
|
||||||
|
|
||||||
|
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||||
|
elsif params[:choice][:state] == 'routage_simple'
|
||||||
|
redirect_to simple_routing_admin_procedure_groupe_instructeurs_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_all_groups_but_defaut
|
||||||
|
reaffecter_all_dossiers_to_defaut_groupe
|
||||||
|
procedure.groupe_instructeurs_but_defaut.each(&:destroy!)
|
||||||
|
procedure.update!(routing_enabled: false, instructeurs_self_management_enabled: false)
|
||||||
|
procedure.defaut_groupe_instructeur.update!(
|
||||||
|
routing_rule: nil,
|
||||||
|
label: GroupeInstructeur::DEFAUT_LABEL,
|
||||||
|
closed: false
|
||||||
|
)
|
||||||
|
flash.notice = 'Tous les groupes instructeurs ont été supprimés'
|
||||||
|
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@procedure = procedure
|
@procedure = procedure
|
||||||
@groupe_instructeur = groupe_instructeur
|
@groupe_instructeur = groupe_instructeur
|
||||||
|
@ -48,10 +116,7 @@ module Administrateurs
|
||||||
def update
|
def update
|
||||||
@groupe_instructeur = groupe_instructeur
|
@groupe_instructeur = groupe_instructeur
|
||||||
|
|
||||||
if closed_params? && @groupe_instructeur.id == procedure.defaut_groupe_instructeur.id
|
if @groupe_instructeur.update(groupe_instructeur_params)
|
||||||
redirect_to admin_procedure_groupe_instructeur_path(procedure, groupe_instructeur),
|
|
||||||
alert: "Il est impossible de désactiver le groupe d’instructeurs par défaut."
|
|
||||||
elsif @groupe_instructeur.update(groupe_instructeur_params)
|
|
||||||
redirect_to admin_procedure_groupe_instructeur_path(procedure, groupe_instructeur),
|
redirect_to admin_procedure_groupe_instructeur_path(procedure, groupe_instructeur),
|
||||||
notice: "Le nom est à présent « #{@groupe_instructeur.label} »."
|
notice: "Le nom est à présent « #{@groupe_instructeur.label} »."
|
||||||
else
|
else
|
||||||
|
@ -64,6 +129,26 @@ module Administrateurs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_state
|
||||||
|
@groupe_instructeur = procedure.groupe_instructeurs.find(params[:groupe_instructeur_id])
|
||||||
|
|
||||||
|
if closed_params? && @groupe_instructeur.id == procedure.defaut_groupe_instructeur.id
|
||||||
|
redirect_to admin_procedure_groupe_instructeur_path(procedure, @groupe_instructeur),
|
||||||
|
alert: "Il est impossible de désactiver le groupe d’instructeurs par défaut."
|
||||||
|
elsif @groupe_instructeur.update(closed: params[:closed])
|
||||||
|
state_for_notice = @groupe_instructeur.closed ? 'désactivé' : 'activé'
|
||||||
|
redirect_to admin_procedure_groupe_instructeur_path(procedure, @groupe_instructeur),
|
||||||
|
notice: "Le groupe #{@groupe_instructeur.label} est #{state_for_notice}."
|
||||||
|
else
|
||||||
|
@procedure = procedure
|
||||||
|
@instructeurs = paginated_instructeurs
|
||||||
|
@available_instructeur_emails = available_instructeur_emails
|
||||||
|
|
||||||
|
flash.now[:alert] = @groupe_instructeur.errors.full_messages
|
||||||
|
render :show
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@groupe_instructeur = groupe_instructeur
|
@groupe_instructeur = groupe_instructeur
|
||||||
|
|
||||||
|
@ -76,7 +161,15 @@ module Administrateurs
|
||||||
else
|
else
|
||||||
@groupe_instructeur.destroy!
|
@groupe_instructeur.destroy!
|
||||||
if procedure.groupe_instructeurs.active.one?
|
if procedure.groupe_instructeurs.active.one?
|
||||||
procedure.update!(routing_enabled: false)
|
procedure.update!(
|
||||||
|
routing_enabled: false,
|
||||||
|
instructeurs_self_management_enabled: false
|
||||||
|
)
|
||||||
|
procedure.defaut_groupe_instructeur.update!(
|
||||||
|
routing_rule: nil,
|
||||||
|
label: GroupeInstructeur::DEFAUT_LABEL,
|
||||||
|
closed: false
|
||||||
|
)
|
||||||
routing_notice = " et le routage a été désactivé"
|
routing_notice = " et le routage a été désactivé"
|
||||||
end
|
end
|
||||||
flash[:notice] = "le groupe « #{@groupe_instructeur.label} » a été supprimé#{routing_notice}."
|
flash[:notice] = "le groupe « #{@groupe_instructeur.label} » a été supprimé#{routing_notice}."
|
||||||
|
@ -112,6 +205,14 @@ module Administrateurs
|
||||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reaffecter_all_dossiers_to_defaut_groupe
|
||||||
|
procedure.groupe_instructeurs_but_defaut.each do |gi|
|
||||||
|
gi.dossiers.find_each do |dossier|
|
||||||
|
dossier.assign_to_groupe_instructeur(procedure.defaut_groupe_instructeur, current_administrateur)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def add_instructeur
|
def add_instructeur
|
||||||
emails = params['emails'].presence || [].to_json
|
emails = params['emails'].presence || [].to_json
|
||||||
emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) }
|
emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) }
|
||||||
|
@ -193,7 +294,7 @@ module Administrateurs
|
||||||
def update_instructeurs_self_management_enabled
|
def update_instructeurs_self_management_enabled
|
||||||
procedure.update!(instructeurs_self_management_enabled_params)
|
procedure.update!(instructeurs_self_management_enabled_params)
|
||||||
|
|
||||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure),
|
redirect_to options_admin_procedure_groupe_instructeurs_path(procedure),
|
||||||
notice: "L’autogestion des instructeurs est #{procedure.instructeurs_self_management_enabled? ? "activée" : "désactivée"}."
|
notice: "L’autogestion des instructeurs est #{procedure.instructeurs_self_management_enabled? ? "activée" : "désactivée"}."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -264,7 +365,7 @@ module Administrateurs
|
||||||
private
|
private
|
||||||
|
|
||||||
def closed_params?
|
def closed_params?
|
||||||
groupe_instructeur_params[:closed] == "1"
|
params[:closed] == "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
def procedure
|
def procedure
|
||||||
|
@ -287,12 +388,21 @@ module Administrateurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def groupe_instructeur_params
|
def groupe_instructeur_params
|
||||||
params.require(:groupe_instructeur).permit(:label, :closed)
|
params.require(:groupe_instructeur).permit(:label)
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginated_groupe_instructeurs
|
def paginated_groupe_instructeurs
|
||||||
procedure
|
groupes = if params[:q].present?
|
||||||
.groupe_instructeurs
|
query = ActiveRecord::Base.sanitize_sql_like(params[:q])
|
||||||
|
|
||||||
|
procedure
|
||||||
|
.groupe_instructeurs
|
||||||
|
.where('unaccent(label) ILIKE unaccent(?)', "%#{query}%")
|
||||||
|
else
|
||||||
|
procedure.groupe_instructeurs
|
||||||
|
end
|
||||||
|
|
||||||
|
groupes
|
||||||
.page(params[:page])
|
.page(params[:page])
|
||||||
.per(ITEMS_PER_PAGE)
|
.per(ITEMS_PER_PAGE)
|
||||||
end
|
end
|
||||||
|
|
|
@ -179,7 +179,6 @@ module Users
|
||||||
errors = submit_dossier_and_compute_errors
|
errors = submit_dossier_and_compute_errors
|
||||||
|
|
||||||
if errors.blank?
|
if errors.blank?
|
||||||
RoutingEngine.compute(@dossier)
|
|
||||||
@dossier.passer_en_construction!
|
@dossier.passer_en_construction!
|
||||||
@dossier.process_declarative!
|
@dossier.process_declarative!
|
||||||
NotificationMailer.send_en_construction_notification(@dossier).deliver_later
|
NotificationMailer.send_en_construction_notification(@dossier).deliver_later
|
||||||
|
@ -538,9 +537,7 @@ module Users
|
||||||
@dossier.assign_to_groupe_instructeur(defaut_groupe_instructeur)
|
@dossier.assign_to_groupe_instructeur(defaut_groupe_instructeur)
|
||||||
end
|
end
|
||||||
|
|
||||||
if !@dossier.procedure.feature_enabled?(:routing_rules) && @dossier.groupe_instructeur.nil?
|
RoutingEngine.compute(@dossier)
|
||||||
errors += format_errors(errors: ["Le champ « #{@dossier.procedure.routing_criteria_name} » doit être rempli"])
|
|
||||||
end
|
|
||||||
|
|
||||||
errors
|
errors
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,6 +26,16 @@ module Mutations
|
||||||
.build(label: groupe_instructeur.label, closed: groupe_instructeur.closed, instructeurs: [current_administrateur.instructeur].compact)
|
.build(label: groupe_instructeur.label, closed: groupe_instructeur.closed, instructeurs: [current_administrateur.instructeur].compact)
|
||||||
|
|
||||||
if groupe_instructeur.save
|
if groupe_instructeur.save
|
||||||
|
|
||||||
|
# ugly hack to keep retro compatibility
|
||||||
|
# do not judge
|
||||||
|
if !ENV['OLD_GROUPE_INSTRUCTEURS_CREATE_API_PROCEDURE_ID'].nil? && demarche_number.in?(ENV['OLD_GROUPE_INSTRUCTEURS_CREATE_API_PROCEDURE_ID']&.split(',')&.map(&:to_i))
|
||||||
|
stable_id = procedure.groupe_instructeurs.first.routing_rule.left.stable_id
|
||||||
|
tdc = procedure.published_revision.types_de_champ.find_by(stable_id: stable_ids)
|
||||||
|
tdc.update(options: tdc.options['drop_down_options'].push(groupe_instructeur.label))
|
||||||
|
groupe_instructeur.update(routing_rule: ds_eq(champ_value(stable_id), constant(groupe_instruteur.label)))
|
||||||
|
end
|
||||||
|
|
||||||
result = { groupe_instructeur: }
|
result = { groupe_instructeur: }
|
||||||
|
|
||||||
if emails.present? || ids.present?
|
if emails.present? || ids.present?
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Controller } from '@hotwired/stimulus';
|
||||||
|
|
||||||
|
export class RadioEnabledSubmitController extends Controller {
|
||||||
|
static targets = ['submit'];
|
||||||
|
declare readonly submitTarget: HTMLButtonElement;
|
||||||
|
|
||||||
|
click() {
|
||||||
|
if (
|
||||||
|
this.element.querySelectorAll('input[type="radio"]:checked').length > 0
|
||||||
|
) {
|
||||||
|
this.submitTarget.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,10 +86,22 @@ class GroupeInstructeur < ApplicationRecord
|
||||||
dossiers.empty? && (procedure.groupe_instructeurs.active.many? || (procedure.groupe_instructeurs.active.one? && closed))
|
dossiers.empty? && (procedure.groupe_instructeurs.active.many? || (procedure.groupe_instructeurs.active.one? && closed))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def routing_to_configure?
|
||||||
|
rule = routing_rule
|
||||||
|
return true if !(rule.is_a?(Logic::Eq) && rule.left.is_a?(Logic::ChampValue) && rule.right.is_a?(Logic::Constant))
|
||||||
|
!routing_rule_matches_tdc?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def routing_rule_matches_tdc?
|
||||||
|
routing_tdc = procedure.active_revision.types_de_champ.find_by(stable_id: routing_rule.left.stable_id)
|
||||||
|
routing_rule.right.value.in?(routing_tdc.options['drop_down_options'])
|
||||||
|
end
|
||||||
|
|
||||||
def toggle_routing
|
def toggle_routing
|
||||||
procedure.update!(routing_enabled: procedure.groupe_instructeurs.active.many?)
|
procedure.update!(routing_enabled: procedure.groupe_instructeurs.active.many?)
|
||||||
|
procedure.update!(instructeurs_self_management_enabled: true) if procedure.routing_enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
serialize :routing_rule, LogicSerializer
|
serialize :routing_rule, LogicSerializer
|
||||||
|
|
|
@ -728,16 +728,16 @@ class Procedure < ApplicationRecord
|
||||||
revisions.size - 2
|
revisions.size - 2
|
||||||
end
|
end
|
||||||
|
|
||||||
def instructeurs_self_management?
|
|
||||||
routing_enabled? || instructeurs_self_management_enabled?
|
|
||||||
end
|
|
||||||
|
|
||||||
def defaut_groupe_instructeur_for_new_dossier
|
def defaut_groupe_instructeur_for_new_dossier
|
||||||
if !routing_enabled? || feature_enabled?(:procedure_routage_api)
|
if !routing_enabled? || feature_enabled?(:procedure_routage_api)
|
||||||
defaut_groupe_instructeur
|
defaut_groupe_instructeur
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def groupe_instructeurs_but_defaut
|
||||||
|
groupe_instructeurs - [defaut_groupe_instructeur]
|
||||||
|
end
|
||||||
|
|
||||||
def can_be_deleted_by_administrateur?
|
def can_be_deleted_by_administrateur?
|
||||||
brouillon? || dossiers.state_en_instruction.empty?
|
brouillon? || dossiers.state_en_instruction.empty?
|
||||||
end
|
end
|
||||||
|
|
|
@ -236,6 +236,10 @@ class ProcedureRevision < ApplicationRecord
|
||||||
[coordinate, coordinate&.type_de_champ]
|
[coordinate, coordinate&.type_de_champ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def routable_types_de_champ
|
||||||
|
types_de_champ_public.filter { |tdc| [:drop_down_list].include?(tdc.type_champ.to_sym) }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def compute_estimated_fill_duration
|
def compute_estimated_fill_duration
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class ProcedureRevisionChange
|
class ProcedureRevisionChange
|
||||||
|
attr_reader :type_de_champ
|
||||||
def initialize(type_de_champ)
|
def initialize(type_de_champ)
|
||||||
@type_de_champ = type_de_champ
|
@type_de_champ = type_de_champ
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ module RoutingEngine
|
||||||
def self.compute(dossier)
|
def self.compute(dossier)
|
||||||
return if !dossier.procedure.feature_enabled?(:routing_rules)
|
return if !dossier.procedure.feature_enabled?(:routing_rules)
|
||||||
|
|
||||||
matching_groupe = dossier.procedure.groupe_instructeurs.active.find do |gi|
|
matching_groupe = dossier.procedure.groupe_instructeurs.active.reject(&:routing_to_configure?).find do |gi|
|
||||||
gi.routing_rule&.compute(dossier.champs)
|
gi.routing_rule&.compute(dossier.champs)
|
||||||
end
|
end
|
||||||
matching_groupe ||= dossier.procedure.defaut_groupe_instructeur
|
matching_groupe ||= dossier.procedure.defaut_groupe_instructeur
|
||||||
|
|
|
@ -131,6 +131,7 @@ class TypeDeChamp < ApplicationRecord
|
||||||
has_one :procedure, through: :revision
|
has_one :procedure, through: :revision
|
||||||
|
|
||||||
delegate :estimated_fill_duration, :estimated_read_duration, :tags_for_template, :libelle_for_export, to: :dynamic_type
|
delegate :estimated_fill_duration, :estimated_read_duration, :tags_for_template, :libelle_for_export, to: :dynamic_type
|
||||||
|
delegate :used_by_routing_rules?, to: :revision_type_de_champ
|
||||||
|
|
||||||
class WithIndifferentAccess
|
class WithIndifferentAccess
|
||||||
def self.load(options)
|
def self.load(options)
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
- if groupes_instructeurs.many? && !procedure.feature_enabled?(:routing_rules)
|
|
||||||
.card
|
|
||||||
= form_for procedure,
|
|
||||||
url: { action: :update_routing_criteria_name },
|
|
||||||
html: { class: 'form' } do |f|
|
|
||||||
|
|
||||||
= f.label :routing_criteria_name do
|
|
||||||
= t('.routing.title')
|
|
||||||
%p.notice
|
|
||||||
= f.text_field :routing_criteria_name, required: true
|
|
||||||
= f.submit t('.button.rename'), class: 'button primary send'
|
|
||||||
|
|
||||||
.card
|
|
||||||
%h2.card-title= t('.group_management.title')
|
|
||||||
|
|
||||||
= form_for :groupe_instructeur, html: { class: 'form' } do |f|
|
|
||||||
= f.label :label do
|
|
||||||
= t('.add_a_group.title')
|
|
||||||
- if groupes_instructeurs.many?
|
|
||||||
%p.notice
|
|
||||||
= t('.add_a_group.notice', routing_criteria_name: procedure.routing_criteria_name)
|
|
||||||
= f.text_field :label, required: true
|
|
||||||
= f.submit t('.button.add_group'), class: "button primary send"
|
|
||||||
|
|
||||||
- csv_max_size = Administrateurs::GroupeInstructeursController::CSV_MAX_SIZE
|
|
||||||
- if procedure.publiee_or_close?
|
|
||||||
= form_tag import_admin_procedure_groupe_instructeurs_path(procedure), method: :post, multipart: true, class: "mt-4 form" do
|
|
||||||
= label_tag t('.csv_import.title')
|
|
||||||
%p.notice
|
|
||||||
= t('.csv_import.notice_1_html',
|
|
||||||
instructeurs_link: link_to(t('.csv_import.link_text'), t('.csv_import.instructeurs_file_path')),
|
|
||||||
groupes_link: link_to(t('.csv_import.link_text'), t('.csv_import.groupes_file_path')))
|
|
||||||
%p.notice
|
|
||||||
= t('.csv_import.notice_2', csv_max_size: number_to_human_size(csv_max_size))
|
|
||||||
= file_field_tag :csv_file, required: true, accept: 'text/csv', size: "1"
|
|
||||||
= submit_tag t('.csv_import.import_file'), class: 'button primary send', data: { disable_with: "Envoi...", confirm: t('.csv_import.import_file_alert') }
|
|
||||||
- else
|
|
||||||
%p.mt-4.form.font-weight-bold.mb-2.text-lg
|
|
||||||
= t('.csv_import.title')
|
|
||||||
%p.notice
|
|
||||||
= t('.csv_import.import_file_procedure_not_published')
|
|
||||||
- if procedure.groupe_instructeurs.many?
|
|
||||||
%table.table.mt-2
|
|
||||||
%thead
|
|
||||||
%tr
|
|
||||||
// i18n-tasks-use t('.existing_groupe')
|
|
||||||
%th{ colspan: 2 }= t(".existing_groupe", count: groupes_instructeurs.total_count)
|
|
||||||
%th.actions
|
|
||||||
= link_to "Exporter au format CSV", export_groupe_instructeurs_admin_procedure_groupe_instructeurs_path(procedure, format: :csv)
|
|
||||||
%tbody
|
|
||||||
- groupes_instructeurs.each do |group|
|
|
||||||
%tr
|
|
||||||
%td= group.label
|
|
||||||
%td.setup= link_to t('.set_up'), admin_procedure_groupe_instructeur_path(procedure, group)
|
|
||||||
- if group.can_delete?
|
|
||||||
%td.actions
|
|
||||||
= link_to admin_procedure_groupe_instructeur_path(procedure, group), { method: :delete, class: 'button', data: { confirm: t('.group_management.delete_confirmation', group_name: group.label) }} do
|
|
||||||
%span.icon.delete
|
|
||||||
= t('.group_management.delete')
|
|
||||||
- else
|
|
||||||
%td.actions
|
|
||||||
= link_to reaffecter_dossiers_admin_procedure_groupe_instructeur_path(procedure, group), class: 'button', title: t('.group_management.move_files_confirmation') do
|
|
||||||
%span.icon.follow
|
|
||||||
= t('.group_management.move_files', count: group.dossiers.visible_by_administration.size)
|
|
||||||
|
|
||||||
|
|
||||||
= paginate groupes_instructeurs, views_prefix: 'shared'
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
- key = @procedure.groupe_instructeurs.one? ? 'instructeurs' : 'groupes'
|
||||||
|
%section.fr-accordion.fr-mb-3w
|
||||||
|
%h3.fr-accordion__title
|
||||||
|
%button.fr-accordion__btn{ "aria-controls" => "accordion-106", "aria-expanded" => "false" }
|
||||||
|
= t(".csv_import.#{key}.title")
|
||||||
|
.fr-collapse#accordion-106
|
||||||
|
- csv_max_size = Administrateurs::GroupeInstructeursController::CSV_MAX_SIZE
|
||||||
|
- if procedure.publiee_or_close?
|
||||||
|
%p.notice
|
||||||
|
= t(".csv_import.#{key}.notice_1_html", csv_max_size: number_to_human_size(csv_max_size))
|
||||||
|
%p.notice
|
||||||
|
= t(".csv_import.#{key}.notice_2")
|
||||||
|
= form_tag import_admin_procedure_groupe_instructeurs_path(@procedure), method: :post, multipart: true, class: "mt-4 form flex justify-between align-center" do
|
||||||
|
= file_field_tag :csv_file, required: true, accept: 'text/csv', size: "1"
|
||||||
|
= submit_tag t('.csv_import.import_file'), class: 'fr-btn fr-btn--secondary', data: { disable_with: "Envoi...", confirm: t('.csv_import.import_file_alert') }
|
||||||
|
- else
|
||||||
|
%p.mt-4.form.font-weight-bold.mb-2.text-lg
|
||||||
|
= t(".csv_import.#{key}.title")
|
||||||
|
%p.notice
|
||||||
|
= t('.csv_import.import_file_procedure_not_published')
|
||||||
|
- if groupe_instructeurs.many?
|
||||||
|
.flex.justify-between.align-center.mt-4
|
||||||
|
%div
|
||||||
|
= t(".existing_groupe", count: groupe_instructeurs.total_count)
|
||||||
|
= button_to "Exporter au format CSV",
|
||||||
|
export_groupe_instructeurs_admin_procedure_groupe_instructeurs_path(@procedure, format: :csv),
|
||||||
|
method: :get,
|
||||||
|
class: 'fr-btn fr-btn--secondary'
|
|
@ -1,14 +0,0 @@
|
||||||
.card
|
|
||||||
%h2.card-title L’autogestion des instructeurs
|
|
||||||
%p.notice= t('.self_managment_notice_html')
|
|
||||||
|
|
||||||
= form_for procedure,
|
|
||||||
method: :patch,
|
|
||||||
url: update_instructeurs_self_management_enabled_admin_procedure_groupe_instructeurs_path(procedure),
|
|
||||||
data: { controller: 'autosubmit', turbo: 'true' },
|
|
||||||
html: { class: 'form procedure-form__column--form no-background' } do |f|
|
|
||||||
%label.toggle-switch
|
|
||||||
= f.check_box :instructeurs_self_management_enabled, class: 'toggle-switch-checkbox'
|
|
||||||
%span.toggle-switch-control.round
|
|
||||||
%span.toggle-switch-label.on
|
|
||||||
%span.toggle-switch-label.off
|
|
|
@ -1,4 +0,0 @@
|
||||||
.card
|
|
||||||
%h2.card-title= t('.title')
|
|
||||||
|
|
||||||
%p.notice= t('.notice_html')
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
= render partial: 'administrateurs/breadcrumbs',
|
||||||
|
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
||||||
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
|
[(@procedure.groupe_instructeurs.many? ? 'Groupes' : 'Instructeurs'), admin_procedure_groupe_instructeurs_path(@procedure)],
|
||||||
|
['Ajout']] }
|
||||||
|
|
||||||
|
= render Procedure::InstructeursMenuComponent.new(procedure: @procedure) do
|
||||||
|
= render Procedure::GroupesAjoutComponent.new(procedure: @procedure, groupe_instructeurs: @groupes_instructeurs)
|
|
@ -1,31 +1,14 @@
|
||||||
- if @procedure.routing_enabled?
|
= render partial: 'administrateurs/breadcrumbs',
|
||||||
= render partial: 'administrateurs/breadcrumbs',
|
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
||||||
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
[@procedure.groupe_instructeurs.many? ? 'Groupes' : 'Instructeurs']] }
|
||||||
[t('.instructors_group')]] }
|
|
||||||
- else
|
|
||||||
= render partial: 'administrateurs/breadcrumbs',
|
|
||||||
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
|
||||||
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
|
||||||
['Instructeurs']] }
|
|
||||||
|
|
||||||
.container.groupe-instructeur
|
|
||||||
%h1 Gérer les instructeurs et les options d'instruction de « #{@procedure.libelle} »
|
|
||||||
|
|
||||||
|
= render Procedure::InstructeursMenuComponent.new(procedure: @procedure) do
|
||||||
- if @procedure.groupe_instructeurs.one?
|
- if @procedure.groupe_instructeurs.one?
|
||||||
= render partial: 'administrateurs/groupe_instructeurs/instructeurs',
|
= render Procedure::InstructeursManagementComponent.new(procedure: @procedure,
|
||||||
locals: { procedure: @procedure,
|
groupe_instructeur: @procedure.groupe_instructeurs.first,
|
||||||
groupe_instructeur: @procedure.defaut_groupe_instructeur,
|
instructeurs: @instructeurs,
|
||||||
instructeurs: @instructeurs,
|
available_instructeur_emails: @available_instructeur_emails,
|
||||||
available_instructeur_emails: @available_instructeur_emails,
|
disabled_as_super_admin: administrateur_as_manager?)
|
||||||
disabled_as_super_admin: administrateur_as_manager? }
|
- else
|
||||||
- if !@procedure.routing_enabled?
|
= render Procedure::GroupesManagementComponent.new(procedure: @procedure, groupe_instructeurs: @groupes_instructeurs, query: params[:q])
|
||||||
= render partial: 'administrateurs/groupe_instructeurs/instructeurs_self_management', locals: { procedure: @procedure }
|
|
||||||
|
|
||||||
= render partial: 'administrateurs/groupe_instructeurs/routing', locals: { procedure: @procedure }
|
|
||||||
|
|
||||||
= render partial: 'administrateurs/groupe_instructeurs/edit', locals: { procedure: @procedure, groupes_instructeurs: @groupes_instructeurs }
|
|
||||||
|
|
||||||
- if @procedure.routing_enabled? && @procedure.feature_enabled?(:routing_rules)
|
|
||||||
= render(Procedure::RoutingRulesComponent.new(revision: @procedure.active_revision,
|
|
||||||
groupe_instructeurs: @procedure.groupe_instructeurs))
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
= render partial: 'administrateurs/breadcrumbs',
|
||||||
|
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
||||||
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
|
[(@procedure.groupe_instructeurs.many? ? 'Groupes' : 'Instructeurs'), admin_procedure_groupe_instructeurs_path(@procedure)],
|
||||||
|
['Options']] }
|
||||||
|
|
||||||
|
= render Procedure::InstructeursMenuComponent.new(procedure: @procedure) do
|
||||||
|
= render Procedure::InstructeursOptionsComponent.new(procedure: @procedure, state: params[:state])
|
|
@ -4,8 +4,9 @@
|
||||||
['Groupes d’instructeurs', admin_procedure_groupe_instructeurs_path(@procedure)],
|
['Groupes d’instructeurs', admin_procedure_groupe_instructeurs_path(@procedure)],
|
||||||
[@groupe_instructeur.label]] }
|
[@groupe_instructeur.label]] }
|
||||||
|
|
||||||
.container.groupe-instructeur
|
= render Procedure::InstructeursMenuComponent.new(procedure: @procedure) do
|
||||||
= render partial: 'administrateurs/groups_header'
|
= render Procedure::OneGroupeManagementComponent.new(revision: @procedure.active_revision, groupe_instructeur: @groupe_instructeur)
|
||||||
|
|
||||||
= render partial: 'administrateurs/groupe_instructeurs/instructeurs',
|
= render partial: 'administrateurs/groupe_instructeurs/instructeurs',
|
||||||
locals: { procedure: @procedure,
|
locals: { procedure: @procedure,
|
||||||
groupe_instructeur: @groupe_instructeur,
|
groupe_instructeur: @groupe_instructeur,
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
= render partial: 'administrateurs/breadcrumbs',
|
||||||
|
locals: { steps: [[t('.procedures'), admin_procedures_path],
|
||||||
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
|
['Groupes', admin_procedure_groupe_instructeurs_path(@procedure)],
|
||||||
|
['Routage à partir d’un champ']] }
|
||||||
|
|
||||||
|
= render Procedure::InstructeursMenuComponent.new(procedure: @procedure) do
|
||||||
|
- content_for(:title, 'Routage')
|
||||||
|
%h1 Routage à partir d’un champ
|
||||||
|
= form_for :create_simple_routing,
|
||||||
|
method: :post,
|
||||||
|
data: { controller: 'radio-enabled-submit' },
|
||||||
|
url: create_simple_routing_admin_procedure_groupe_instructeurs_path(@procedure) do |f|
|
||||||
|
|
||||||
|
%div{ data: { 'action': "click->radio-enabled-submit#click" } }
|
||||||
|
.notice
|
||||||
|
Sélectionner le champ à partir duquel créer des groupes d'instructeurs
|
||||||
|
- buttons_content = @procedure.active_revision.routable_types_de_champ.map { |tdc| { label: tdc.libelle, value: tdc.stable_id } }
|
||||||
|
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||||
|
target: :stable_id,
|
||||||
|
buttons: buttons_content)
|
||||||
|
|
||||||
|
%ul.fr-btns-group.fr-btns-group--inline-sm
|
||||||
|
%li
|
||||||
|
= link_to 'Retour', options_admin_procedure_groupe_instructeurs_path(@procedure, state: :choix), class: 'fr-btn fr-btn--secondary'
|
||||||
|
%li
|
||||||
|
%button.fr-btn{ disabled: true, data: { 'radio-enabled-submit-target': 'submit' } } Créer les groupes
|
|
@ -1,2 +1,3 @@
|
||||||
= turbo_stream.replace 'routing-rules', render(Procedure::RoutingRulesComponent.new(revision: @procedure.active_revision,
|
= turbo_stream.replace dom_id(@groupe_instructeur, :routing),
|
||||||
groupe_instructeurs: @procedure.groupe_instructeurs))
|
render(Procedure::OneGroupeManagementComponent.new(revision: @procedure.active_revision,
|
||||||
|
groupe_instructeur: @groupe_instructeur))
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
|
|
||||||
= link_to t('instructeurs.dossiers.header.banner.statistics'), stats_instructeur_procedure_path(procedure), class: 'header-link'
|
= link_to t('instructeurs.dossiers.header.banner.statistics'), stats_instructeur_procedure_path(procedure), class: 'header-link'
|
||||||
|
|
||||||
- if procedure.instructeurs_self_management?
|
- if procedure.instructeurs_self_management_enabled?
|
||||||
|
|
|
|
||||||
- if can_manage_groupe_instructeurs?(procedure)
|
- if can_manage_groupe_instructeurs?(procedure)
|
||||||
= link_to t('instructeurs.dossiers.header.banner.instructeurs'), admin_procedure_groupe_instructeurs_path(procedure), class: 'header-link'
|
= link_to t('instructeurs.dossiers.header.banner.instructeurs'), admin_procedure_groupe_instructeurs_path(procedure), class: 'header-link'
|
||||||
|
|
|
@ -8,7 +8,6 @@ en:
|
||||||
groupe_instructeurs:
|
groupe_instructeurs:
|
||||||
index:
|
index:
|
||||||
procedures: Procedures
|
procedures: Procedures
|
||||||
instructors_group: Group of instructors
|
|
||||||
add_instructeur:
|
add_instructeur:
|
||||||
wrong_address:
|
wrong_address:
|
||||||
one: "%{emails} is not a valid email address"
|
one: "%{emails} is not a valid email address"
|
||||||
|
@ -24,48 +23,19 @@ en:
|
||||||
assigned_instructeur:
|
assigned_instructeur:
|
||||||
one: "%{count} instructor is assigned"
|
one: "%{count} instructor is assigned"
|
||||||
other: "%{count} instructors are assigned"
|
other: "%{count} instructors are assigned"
|
||||||
edit:
|
import_export:
|
||||||
routing:
|
|
||||||
title: Label of the groups list
|
|
||||||
group_management:
|
|
||||||
title: Group management
|
|
||||||
delete: delete the group
|
|
||||||
delete_confirmation: Are you sure you want to delete the group "%{group_name}"
|
|
||||||
move_files:
|
|
||||||
zero: move draft files
|
|
||||||
one: move one file
|
|
||||||
other: move the %{count} files
|
|
||||||
move_files_confirmation: Reassign folders to another group so you can delete it
|
|
||||||
add_a_group:
|
|
||||||
title: Add a group
|
|
||||||
notice: This group will be a choice from the list "%{routing_criteria_name}"
|
|
||||||
csv_import:
|
csv_import:
|
||||||
title: CSV Import
|
import_file: Importer le fichier
|
||||||
notice_1_html: The csv file must have 1 column with instructors emails(%{instructeurs_link}). For routed procedures, the csv file must have 2 columns (Group, Email) and be separated by commas (%{groupes_link}). The import does not overwrite existing groups and instructors.
|
import_file_alert: Tous les instructeurs ajoutés à la procédure vont être notifiés par email. Voulez-vous continuer ?
|
||||||
notice_2: The size of the file must be less than %{csv_max_size}.
|
import_file_procedure_not_published: L’import par fichier CSV est disponible une fois la démarche publiée
|
||||||
import_file: Import file
|
groupes:
|
||||||
import_file_procedure_not_published: The import of instructors by CSV file is available once the process has been published
|
title: Import / Export en masse
|
||||||
import_file_alert: Instructors added to the procedure will receive an email. Are you sure you want to continue ?"
|
notice_1_html: Pour l'import, votre fichier csv doit comporter 2 colonnes (Groupe, Email) et être séparé par des virgules (<a href=/csv/fr/import-groupe-test.csv>exemple de fichier</a>). Le poids du fichier doit être inférieur %{csv_max_size}.
|
||||||
link_text: file example
|
notice_2: L’import n’écrase pas les groupes existants. Il permet uniquement d'en ajouter. Pour supprimer un groupe, allez dans la page dédiée et cliquez sur le bouton « Supprimer ».
|
||||||
instructeurs_file_path: /csv/import-instructeurs-test.csv
|
instructeurs:
|
||||||
groupes_file_path: /csv/en/import-groupe-test.csv
|
title: Import en masse
|
||||||
set_up: set up
|
notice_1_html: Pour l'import, le fichier csv doit comporter 1 seule colonne (Email) avec une adresse email d'instructeur par ligne (<a href=/csv/import-instructeurs-test.csv>exemple de fichier</a>). Le poids du fichier doit être inférieur %{csv_max_size}.
|
||||||
button:
|
notice_2: L’import n’écrase pas les instructeurs existants. Il permet uniquement d'en ajouter. Pour supprimer un instructeur, cliquez sur le bouton « Retirer ».
|
||||||
add_group: Add group
|
|
||||||
rename: Rename
|
|
||||||
existing_groupe:
|
existing_groupe:
|
||||||
one: "%{count} group exist"
|
one: "%{count} groupe existe"
|
||||||
other: "%{count} groups exist"
|
other: "%{count} groupes existent"
|
||||||
routing:
|
|
||||||
title: Routing
|
|
||||||
notice_html: |
|
|
||||||
Routing is a feature for procedures requiring the sharing of instructions between different groups according to a specific criterion (territory, theme or other).
|
|
||||||
<br><br>
|
|
||||||
This feature makes it possible to route the files to each group, and to no longer need to filter its files among a large quantity of requests. It is therefore particularly suitable for national approaches instructed locally.
|
|
||||||
<br><br>
|
|
||||||
Instructors only see the files that concern them, and therefore do not have access to data outside their scope.
|
|
||||||
<br><br>
|
|
||||||
Routing is activated once there are at least two active instructors groups
|
|
||||||
instructeurs_self_management:
|
|
||||||
self_managment_notice_html: |
|
|
||||||
Instructor Self-Management allows instructors to self-manage the list of Gait Instructors.
|
|
||||||
|
|
|
@ -30,6 +30,34 @@ fr:
|
||||||
assigned_instructeur:
|
assigned_instructeur:
|
||||||
one: "%{count} instructeur est affecté"
|
one: "%{count} instructeur est affecté"
|
||||||
other: "%{count} instructeurs sont affectés"
|
other: "%{count} instructeurs sont affectés"
|
||||||
|
import_export:
|
||||||
|
csv_import:
|
||||||
|
import_file: Importer le fichier
|
||||||
|
import_file_alert: Tous les instructeurs ajoutés à la procédure vont être notifiés par email. Voulez-vous continuer ?
|
||||||
|
import_file_procedure_not_published: L’import par fichier CSV est disponible une fois la démarche publiée
|
||||||
|
groupes:
|
||||||
|
title: Import / Export en masse
|
||||||
|
notice_1_html: Pour l'import, votre fichier csv doit comporter 2 colonnes (Groupe, Email) et être séparé par des virgules (<a href=/csv/fr/import-groupe-test.csv>exemple de fichier</a>). Le poids du fichier doit être inférieur %{csv_max_size}.
|
||||||
|
notice_2: L’import n’écrase pas les groupes existants. Il permet uniquement d'en ajouter. Pour supprimer un groupe, allez dans la page dédiée et cliquez sur le bouton « Supprimer ».
|
||||||
|
instructeurs:
|
||||||
|
title: Import en masse
|
||||||
|
notice_1_html: Pour l'import, le fichier csv doit comporter 1 seule colonne (Email) avec une adresse email d'instructeur par ligne (<a href=/csv/import-instructeurs-test.csv>exemple de fichier</a>). Le poids du fichier doit être inférieur %{csv_max_size}.
|
||||||
|
notice_2: L’import n’écrase pas les instructeurs existants. Il permet uniquement d'en ajouter. Pour supprimer un instructeur, cliquez sur le bouton « Retirer ».
|
||||||
|
existing_groupe:
|
||||||
|
one: "%{count} groupe existe"
|
||||||
|
other: "%{count} groupes existent"
|
||||||
|
groupe:
|
||||||
|
one: "%{count} groupe"
|
||||||
|
other: "%{count} groupes"
|
||||||
|
found:
|
||||||
|
one: "trouvé"
|
||||||
|
other: "trouvés"
|
||||||
|
ajout:
|
||||||
|
procedures: Démarches
|
||||||
|
options:
|
||||||
|
procedures: Démarches
|
||||||
|
simple_routing:
|
||||||
|
procedures: Démarches
|
||||||
edit:
|
edit:
|
||||||
routing:
|
routing:
|
||||||
title: Libellé de la liste de groupes
|
title: Libellé de la liste de groupes
|
||||||
|
@ -46,14 +74,6 @@ fr:
|
||||||
title: Ajouter un nom de groupe
|
title: Ajouter un nom de groupe
|
||||||
notice: Ce groupe sera un choix de la liste "%{routing_criteria_name}"
|
notice: Ce groupe sera un choix de la liste "%{routing_criteria_name}"
|
||||||
csv_import:
|
csv_import:
|
||||||
title: Importer par CSV
|
|
||||||
notice_1_html: |
|
|
||||||
Pour une procédure standard, le fichier csv doit comporter 1 seule colonne (Email) avec une adresse email d'instructeur par ligne (%{instructeurs_link}).
|
|
||||||
Pour une procédure routée, le fichier doit comporter 2 colonnes (Groupe, Email) et être séparé par des virgules (%{groupes_link}).
|
|
||||||
notice_2: L’import n’écrase pas les instructeurs existants. Il permet uniquement d'en ajouter. Pour supprimer un instructeur, cliquez sur le bouton « retirer ». Le poids du fichier doit être inférieur %{csv_max_size}.
|
|
||||||
import_file: Importer le fichier
|
|
||||||
import_file_procedure_not_published: L’import d’instructeurs par fichier CSV est disponible une fois la démarche publiée
|
|
||||||
import_file_alert: Tous les instructeurs ajoutés à la procédure vont être informés par email. Voulez-vous continuer ?
|
|
||||||
link_text: exemple de fichier
|
link_text: exemple de fichier
|
||||||
instructeurs_file_path: /csv/import-instructeurs-test.csv
|
instructeurs_file_path: /csv/import-instructeurs-test.csv
|
||||||
groupes_file_path: /csv/fr/import-groupe-test.csv
|
groupes_file_path: /csv/fr/import-groupe-test.csv
|
||||||
|
@ -72,6 +92,3 @@ fr:
|
||||||
button:
|
button:
|
||||||
self_managment_toggle: Activer l’autogestion des instructeurs
|
self_managment_toggle: Activer l’autogestion des instructeurs
|
||||||
add_group: Ajouter le groupe
|
add_group: Ajouter le groupe
|
||||||
instructeurs_self_management:
|
|
||||||
self_managment_notice_html: |
|
|
||||||
L’autogestion des instructeurs permet aux instructeurs de gérer eux-mêmes la liste des instructeurs de la démarche.
|
|
||||||
|
|
|
@ -522,6 +522,8 @@ Rails.application.routes.draw do
|
||||||
resources :mail_templates, only: [:edit, :update, :show]
|
resources :mail_templates, only: [:edit, :update, :show]
|
||||||
|
|
||||||
resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do
|
resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do
|
||||||
|
patch 'update_state' => 'groupe_instructeurs#update_state'
|
||||||
|
|
||||||
member do
|
member do
|
||||||
post 'add_instructeur'
|
post 'add_instructeur'
|
||||||
delete 'remove_instructeur'
|
delete 'remove_instructeur'
|
||||||
|
@ -530,6 +532,13 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
collection do
|
collection do
|
||||||
|
get 'options'
|
||||||
|
get 'ajout'
|
||||||
|
post 'ajout' => 'groupe_instructeurs#create'
|
||||||
|
patch 'wizard'
|
||||||
|
get 'simple_routing'
|
||||||
|
post 'create_simple_routing'
|
||||||
|
delete 'destroy_all_groups_but_defaut'
|
||||||
patch 'update_routing_criteria_name'
|
patch 'update_routing_criteria_name'
|
||||||
patch 'update_instructeurs_self_management_enabled'
|
patch 'update_instructeurs_self_management_enabled'
|
||||||
post 'import'
|
post 'import'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
describe Procedure::RoutingRulesComponent, type: :component do
|
describe Procedure::OneGroupeManagementComponent, type: :component do
|
||||||
include Logic
|
include Logic
|
||||||
|
|
||||||
describe 'render' do
|
describe 'render' do
|
||||||
|
@ -9,16 +9,7 @@ describe Procedure::RoutingRulesComponent, type: :component do
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
render_inline(described_class.new(revision: procedure.active_revision,
|
render_inline(described_class.new(revision: procedure.active_revision,
|
||||||
groupe_instructeurs: procedure.groupe_instructeurs))
|
groupe_instructeur: procedure.defaut_groupe_instructeur))
|
||||||
end
|
|
||||||
|
|
||||||
context 'when there are no types de champ that can be routed' do
|
|
||||||
before do
|
|
||||||
procedure.publish_revision!
|
|
||||||
procedure.reload
|
|
||||||
subject
|
|
||||||
end
|
|
||||||
it { expect(page).to have_text('Ajoutez ce champ dans la page') }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there are types de champ that can be routed' do
|
context 'when there are types de champ that can be routed' do
|
||||||
|
@ -32,7 +23,7 @@ describe Procedure::RoutingRulesComponent, type: :component do
|
||||||
procedure.reload
|
procedure.reload
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
it { expect(page).to have_text('Router vers') }
|
it { expect(page).to have_text('à configurer') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,8 +1,10 @@
|
||||||
describe Administrateurs::GroupeInstructeursController, type: :controller do
|
describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
render_views
|
render_views
|
||||||
|
include Logic
|
||||||
|
|
||||||
let(:admin) { create(:administrateur) }
|
let(:admin) { create(:administrateur) }
|
||||||
let(:procedure) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
let(:procedure) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
||||||
|
|
||||||
let!(:gi_1_1) { procedure.defaut_groupe_instructeur }
|
let!(:gi_1_1) { procedure.defaut_groupe_instructeur }
|
||||||
let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
||||||
|
|
||||||
|
@ -13,13 +15,25 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
|
|
||||||
describe '#index' do
|
describe '#index' do
|
||||||
context 'of a procedure I own' do
|
context 'of a procedure I own' do
|
||||||
before { get :index, params: { procedure_id: procedure.id } }
|
before { get :index, params: }
|
||||||
|
|
||||||
context 'when a procedure has multiple groups' do
|
context 'when a procedure has multiple groups' do
|
||||||
it { expect(response).to have_http_status(:ok) }
|
let(:params) { { procedure_id: procedure.id } }
|
||||||
it { expect(response.body).to include(gi_1_1.label) }
|
|
||||||
it { expect(response.body).to include(gi_1_2.label) }
|
it do
|
||||||
it { expect(response.body).not_to include(gi_2_2.label) }
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include(gi_1_1.label)
|
||||||
|
expect(response.body).to include(gi_1_2.label)
|
||||||
|
expect(response.body).not_to include(gi_2_2.label)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is a search' do
|
||||||
|
let(:params) { { procedure_id: procedure.id, q: '2' } }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(assigns(:groupes_instructeurs)).to match_array([gi_1_2])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -46,6 +60,45 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
expect(assigns(:available_instructeur_emails)).to match_array(['instructeur_3@ministere-a.gouv.fr', 'instructeur_4@ministere-b.gouv.fr'])
|
expect(assigns(:available_instructeur_emails)).to match_array(['instructeur_3@ministere-a.gouv.fr', 'instructeur_4@ministere-b.gouv.fr'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'group without routing rule' do
|
||||||
|
before { get :show, params: { procedure_id: procedure.id, id: gi_1_1.id } }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include('à configurer')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'group with routing rule matching tdc' do
|
||||||
|
let!(:drop_down_tdc) { create(:type_de_champ_drop_down_list, procedure: procedure, drop_down_options: options) }
|
||||||
|
let(:options) { procedure.groupe_instructeurs.pluck(:label) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
gi_1_1.update(routing_rule: ds_eq(champ_value(drop_down_tdc.stable_id), constant(gi_1_1.label)))
|
||||||
|
get :show, params: { procedure_id: procedure.id, id: gi_1_1.id }
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).not_to include('à configurer')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'group with routing rule not matching tdc' do
|
||||||
|
let!(:drop_down_tdc) { create(:type_de_champ_drop_down_list, procedure: procedure, drop_down_options: options) }
|
||||||
|
let(:options) { ['parmesan', 'brie', 'morbier'] }
|
||||||
|
|
||||||
|
before do
|
||||||
|
gi_1_1.update(routing_rule: ds_eq(champ_value(drop_down_tdc.stable_id), constant(gi_1_1.label)))
|
||||||
|
get :show, params: { procedure_id: procedure.id, id: gi_1_1.id }
|
||||||
|
end
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include('à configurer')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create' do
|
describe '#create' do
|
||||||
|
@ -181,7 +234,6 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
|
|
||||||
describe '#update' do
|
describe '#update' do
|
||||||
let(:new_name) { 'nouveau nom du groupe' }
|
let(:new_name) { 'nouveau nom du groupe' }
|
||||||
let(:closed_value) { '0' }
|
|
||||||
let!(:procedure_non_routee) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
let!(:procedure_non_routee) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
||||||
let!(:gi_1_1) { procedure_non_routee.defaut_groupe_instructeur }
|
let!(:gi_1_1) { procedure_non_routee.defaut_groupe_instructeur }
|
||||||
|
|
||||||
|
@ -190,7 +242,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
params: {
|
params: {
|
||||||
procedure_id: procedure_non_routee.id,
|
procedure_id: procedure_non_routee.id,
|
||||||
id: gi_1_1.id,
|
id: gi_1_1.id,
|
||||||
groupe_instructeur: { label: new_name, closed: closed_value }
|
groupe_instructeur: { label: new_name }
|
||||||
}
|
}
|
||||||
gi_1_1.reload
|
gi_1_1.reload
|
||||||
end
|
end
|
||||||
|
@ -202,18 +254,6 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
expect(flash.notice).to be_present
|
expect(flash.notice).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when we try do disable the default groupe instructeur' do
|
|
||||||
let(:closed_value) { '1' }
|
|
||||||
let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
|
||||||
|
|
||||||
it do
|
|
||||||
expect(subject).to redirect_to admin_procedure_groupe_instructeur_path(procedure_non_routee, gi_1_1)
|
|
||||||
expect(gi_1_1.label).not_to eq(new_name)
|
|
||||||
expect(gi_1_1.closed).to eq(false)
|
|
||||||
expect(flash.alert).to eq('Il est impossible de désactiver le groupe d’instructeurs par défaut.')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the name is already taken' do
|
context 'when the name is already taken' do
|
||||||
let!(:gi_1_2) { procedure_non_routee.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
let!(:gi_1_2) { procedure_non_routee.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
||||||
let(:new_name) { gi_1_2.label }
|
let(:new_name) { gi_1_2.label }
|
||||||
|
@ -225,6 +265,45 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#update_state' do
|
||||||
|
let(:closed_value) { '0' }
|
||||||
|
let!(:procedure_non_routee) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
||||||
|
let!(:gi_1_1) { procedure_non_routee.defaut_groupe_instructeur }
|
||||||
|
let!(:gi_1_2) { procedure_non_routee.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
patch :update_state,
|
||||||
|
params: {
|
||||||
|
procedure_id: procedure_non_routee.id,
|
||||||
|
groupe_instructeur_id: group.id,
|
||||||
|
closed: closed_value
|
||||||
|
}
|
||||||
|
group.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when we try do disable the default groupe instructeur' do
|
||||||
|
let(:closed_value) { '1' }
|
||||||
|
let(:group) { gi_1_1 }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(subject).to redirect_to admin_procedure_groupe_instructeur_path(procedure_non_routee, gi_1_1)
|
||||||
|
expect(gi_1_1.closed).to eq(false)
|
||||||
|
expect(flash.alert).to eq('Il est impossible de désactiver le groupe d’instructeurs par défaut.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when we try do disable the second groupe instructeur' do
|
||||||
|
let(:closed_value) { '1' }
|
||||||
|
let(:group) { gi_1_2 }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(subject).to redirect_to admin_procedure_groupe_instructeur_path(procedure_non_routee, gi_1_2)
|
||||||
|
expect(gi_1_2.closed).to eq(true)
|
||||||
|
expect(flash.notice).to eq('Le groupe groupe instructeur 2 est désactivé.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#add_instructeur_procedure_non_routee' do
|
describe '#add_instructeur_procedure_non_routee' do
|
||||||
# faire la meme chose sur une procedure non routee
|
# faire la meme chose sur une procedure non routee
|
||||||
let(:procedure_non_routee) { create :procedure }
|
let(:procedure_non_routee) { create :procedure }
|
||||||
|
@ -624,4 +703,26 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
|
||||||
|
|
||||||
it { expect(procedure.reload.routing_criteria_name).to eq('new name !') }
|
it { expect(procedure.reload.routing_criteria_name).to eq('new name !') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#create_simple_routing' do
|
||||||
|
let!(:procedure3) do
|
||||||
|
create(:procedure,
|
||||||
|
types_de_champ_public: [
|
||||||
|
{ type: :drop_down_list, libelle: 'Votre ville', options: ['Paris', 'Lyon', 'Marseille'] },
|
||||||
|
{ type: :text, libelle: 'Un champ texte' }
|
||||||
|
],
|
||||||
|
administrateurs: [admin])
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:drop_down_tdc) { procedure3.draft_revision.types_de_champ.first }
|
||||||
|
|
||||||
|
before { post :create_simple_routing, params: { procedure_id: procedure3.id, create_simple_routing: { stable_id: drop_down_tdc.stable_id } } }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(response).to redirect_to(admin_procedure_groupe_instructeurs_path(procedure3))
|
||||||
|
expect(flash.notice).to eq 'Les groupes instructeurs ont été ajoutés'
|
||||||
|
expect(procedure3.groupe_instructeurs.pluck(:label)).to match_array(['Paris', 'Lyon', 'Marseille'])
|
||||||
|
expect(procedure3.reload.defaut_groupe_instructeur.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -412,16 +412,6 @@ describe Users::DossiersController, type: :controller do
|
||||||
it { expect(flash.alert).to eq(["Le champ « l » doit être rempli, #{anchor_to_first_champ}"]) }
|
it { expect(flash.alert).to eq(["Le champ « l » doit être rempli, #{anchor_to_first_champ}"]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a dossier is invalid' do
|
|
||||||
before do
|
|
||||||
allow_any_instance_of(Dossier).to receive(:groupe_instructeur).and_return(double(nil?: true))
|
|
||||||
subject
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(response).to render_template(:brouillon) }
|
|
||||||
it { expect(flash.alert).to eq(["Le champ « Votre ville » doit être rempli"]) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when dossier has no champ' do
|
context 'when dossier has no champ' do
|
||||||
let(:submit_payload) { { id: dossier.id } }
|
let(:submit_payload) { { id: dossier.id } }
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,15 @@ describe RoutingEngine, type: :model do
|
||||||
|
|
||||||
describe '.compute' do
|
describe '.compute' do
|
||||||
let(:procedure) do
|
let(:procedure) do
|
||||||
create(:procedure).tap do |p|
|
create(:procedure,
|
||||||
p.groupe_instructeurs.create(label: 'a second group')
|
types_de_champ_public: [{ type: :drop_down_list, libelle: 'Votre ville', options: ['Paris', 'Lyon', 'Marseille'] }]).tap do |p|
|
||||||
p.groupe_instructeurs.create(label: 'a third group')
|
p.groupe_instructeurs.create(label: 'a second group')
|
||||||
end
|
p.groupe_instructeurs.create(label: 'a third group')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:drop_down_tdc) { procedure.draft_revision.types_de_champ.first }
|
||||||
|
|
||||||
let(:dossier) { create(:dossier, procedure:) }
|
let(:dossier) { create(:dossier, procedure:) }
|
||||||
let(:defaut_groupe) { procedure.defaut_groupe_instructeur }
|
let(:defaut_groupe) { procedure.defaut_groupe_instructeur }
|
||||||
let(:gi_2) { procedure.groupe_instructeurs.find_by(label: 'a second group') }
|
let(:gi_2) { procedure.groupe_instructeurs.find_by(label: 'a second group') }
|
||||||
|
@ -34,13 +37,26 @@ describe RoutingEngine, type: :model do
|
||||||
it { is_expected.to eq(defaut_groupe) }
|
it { is_expected.to eq(defaut_groupe) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a matching rules' do
|
context 'with rules not configured yet' do
|
||||||
before { gi_2.update(routing_rule: constant(true)) }
|
before do
|
||||||
|
procedure.groupe_instructeurs.each do |gi|
|
||||||
|
gi.update(routing_rule: ds_eq(empty, empty))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to eq(defaut_groupe) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a matching rule' do
|
||||||
|
before do
|
||||||
|
gi_2.update(routing_rule: ds_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
|
||||||
|
dossier.champs.first.update(value: 'Lyon')
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.to eq(gi_2) }
|
it { is_expected.to eq(gi_2) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a closed gi with a matching rules' do
|
context 'with a closed gi with a matching rule' do
|
||||||
before { gi_2.update(routing_rule: constant(true), closed: true) }
|
before { gi_2.update(routing_rule: constant(true), closed: true) }
|
||||||
|
|
||||||
it { is_expected.to eq(defaut_groupe) }
|
it { is_expected.to eq(defaut_groupe) }
|
||||||
|
|
|
@ -17,24 +17,7 @@ describe 'Manage procedure instructeurs', js: true do
|
||||||
scenario 'it works' do
|
scenario 'it works' do
|
||||||
visit admin_procedure_path(procedure)
|
visit admin_procedure_path(procedure)
|
||||||
find('#groupe-instructeurs').click
|
find('#groupe-instructeurs').click
|
||||||
expect(page).to have_css("h1", text: "Gérer les instructeurs et les options d'instruction de « #{procedure.libelle} »")
|
expect(page).to have_css("h1", text: "Gestion des instructeurs")
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'as admin not from manager' do
|
|
||||||
let(:manager) { false }
|
|
||||||
|
|
||||||
scenario 'can add instructeur' do
|
|
||||||
visit admin_procedure_groupe_instructeurs_path(procedure)
|
|
||||||
expect {
|
|
||||||
fill_in "instructeur_emails", with: create(:instructeur).email
|
|
||||||
click_on "Affecter"
|
|
||||||
}.to change { procedure.instructeurs.count }.by(1)
|
|
||||||
expect {
|
|
||||||
fill_in "groupe_instructeur_label", with: "Bordeaux"
|
|
||||||
click_on "Ajouter le groupe"
|
|
||||||
}.to change { procedure.groupe_instructeurs.count }.by(1)
|
|
||||||
expect(procedure.reload.routing_enabled).to eq true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
describe 'As an administrateur I can manage procedure routing', js: true do
|
|
||||||
include Logic
|
|
||||||
|
|
||||||
let(:administrateur) { procedure.administrateurs.first }
|
|
||||||
let!(:gi_1) { procedure.defaut_groupe_instructeur }
|
|
||||||
let!(:gi_2) { procedure.groupe_instructeurs.create(label: 'a second group') }
|
|
||||||
let!(:gi_3) { procedure.groupe_instructeurs.create(label: 'a third group') }
|
|
||||||
|
|
||||||
let(:procedure) do
|
|
||||||
create(:procedure).tap do |p|
|
|
||||||
p.draft_revision.add_type_de_champ(
|
|
||||||
type_champ: :drop_down_list,
|
|
||||||
libelle: 'Un champ choix simple',
|
|
||||||
options: { "drop_down_other" => "0", "drop_down_options" => ["", "Premier choix", "Deuxième choix", "Troisième choix"] }
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:drop_down_tdc) { procedure.draft_revision.types_de_champ.first }
|
|
||||||
|
|
||||||
before do
|
|
||||||
Flipper.enable(:routing_rules, procedure)
|
|
||||||
procedure.publish_revision!
|
|
||||||
login_as administrateur.user, scope: :user
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'routes from a drop_down_list' do
|
|
||||||
visit admin_procedure_groupe_instructeurs_path(procedure)
|
|
||||||
|
|
||||||
within('.condition-table tbody tr:nth-child(1)', match: :first) do
|
|
||||||
expect(page).to have_select('targeted_champ', options: ['Sélectionner', 'Un champ choix simple'])
|
|
||||||
within('.target') { select('Un champ choix simple') }
|
|
||||||
within('.value') { select('Premier choix') }
|
|
||||||
end
|
|
||||||
|
|
||||||
expected_routing_rule = ds_eq(champ_value(drop_down_tdc.stable_id), constant('Premier choix'))
|
|
||||||
wait_until { gi_2.reload.routing_rule == expected_routing_rule }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'displays groupes instructeurs by alphabetic order' do
|
|
||||||
visit admin_procedure_groupe_instructeurs_path(procedure)
|
|
||||||
|
|
||||||
within('.condition-table tbody tr:nth-child(1)', match: :first) do
|
|
||||||
expect(page).to have_content 'second group'
|
|
||||||
expect(page).not_to have_content 'défaut'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,238 +0,0 @@
|
||||||
describe 'The routing', js: true do
|
|
||||||
let(:password) { 'a very complicated password' }
|
|
||||||
let(:procedure) { create(:procedure, :with_type_de_champ, :with_service, :for_individual, :with_zone) }
|
|
||||||
let(:administrateur) { create(:administrateur, procedures: [procedure]) }
|
|
||||||
let(:scientifique_user) { create(:user, password: password) }
|
|
||||||
let(:litteraire_user) { create(:user, password: password) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
procedure.update(routing_enabled: true)
|
|
||||||
procedure.defaut_groupe_instructeur.instructeurs << administrateur.instructeur
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'works' do
|
|
||||||
login_as administrateur.user, scope: :user
|
|
||||||
visit admin_procedure_path(procedure.id)
|
|
||||||
find('#groupe-instructeurs').click
|
|
||||||
|
|
||||||
# add littéraire groupe
|
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'littéraire'
|
|
||||||
click_on 'Ajouter le groupe'
|
|
||||||
expect(page).to have_text('Le groupe d’instructeurs « littéraire » a été créé et le routage a été activé.')
|
|
||||||
|
|
||||||
# add victor to littéraire groupe
|
|
||||||
fill_in 'Emails', with: 'victor@inst.com'
|
|
||||||
perform_enqueued_jobs { click_on 'Affecter' }
|
|
||||||
expect(page).to have_text("L’instructeur victor@inst.com a été affecté")
|
|
||||||
|
|
||||||
victor = User.find_by(email: 'victor@inst.com').instructeur
|
|
||||||
|
|
||||||
# add superwoman to littéraire groupe
|
|
||||||
fill_in 'Emails', with: 'superwoman@inst.com'
|
|
||||||
perform_enqueued_jobs { click_on 'Affecter' }
|
|
||||||
expect(page).to have_text("L’instructeur superwoman@inst.com a été affecté")
|
|
||||||
|
|
||||||
superwoman = User.find_by(email: 'superwoman@inst.com').instructeur
|
|
||||||
|
|
||||||
# rename routing criteria to spécialité
|
|
||||||
click_on 'Groupes d’instructeurs'
|
|
||||||
fill_in 'Libellé de la liste de groupes', with: 'spécialité'
|
|
||||||
click_on 'Renommer'
|
|
||||||
expect(page).to have_text('Le libellé est maintenant « spécialité ».')
|
|
||||||
expect(page).to have_field('Libellé de la liste de groupes', with: 'spécialité')
|
|
||||||
|
|
||||||
# add inactive groupe
|
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'non visible car inactif'
|
|
||||||
click_on 'Ajouter le groupe'
|
|
||||||
check "Groupe inactif"
|
|
||||||
click_on 'Modifier'
|
|
||||||
|
|
||||||
# add scientifique groupe
|
|
||||||
click_on 'Groupes d’instructeurs'
|
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'scientifique'
|
|
||||||
click_on 'Ajouter le groupe'
|
|
||||||
expect(page).to have_text('Le groupe d’instructeurs « scientifique » a été créé.')
|
|
||||||
|
|
||||||
# add marie to scientifique groupe
|
|
||||||
fill_in 'Emails', with: 'marie@inst.com'
|
|
||||||
perform_enqueued_jobs { click_on 'Affecter' }
|
|
||||||
expect(page).to have_text("L’instructeur marie@inst.com a été affecté")
|
|
||||||
|
|
||||||
marie = User.find_by(email: 'marie@inst.com').instructeur
|
|
||||||
|
|
||||||
# add superwoman to scientifique groupe
|
|
||||||
fill_in 'Emails', with: 'superwoman@inst.com'
|
|
||||||
perform_enqueued_jobs { click_on 'Affecter' }
|
|
||||||
expect(page).to have_text("L’instructeur superwoman@inst.com a été affecté")
|
|
||||||
|
|
||||||
# publish
|
|
||||||
publish_procedure(procedure)
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# 2 users fill a dossier in each group
|
|
||||||
user_send_dossier(scientifique_user, 'scientifique')
|
|
||||||
user_send_dossier(litteraire_user, 'littéraire')
|
|
||||||
|
|
||||||
# the litteraires instructeurs only manage the litteraires dossiers
|
|
||||||
register_instructeur_and_log_in(victor.email)
|
|
||||||
click_on procedure.libelle
|
|
||||||
expect(page).to have_text(litteraire_user.email)
|
|
||||||
expect(page).not_to have_text(scientifique_user.email)
|
|
||||||
|
|
||||||
# the search only show litteraires dossiers
|
|
||||||
fill_in 'q', with: scientifique_user.email
|
|
||||||
find('.fr-search-bar .fr-btn').click
|
|
||||||
expect(page).to have_text('0 dossier trouvé')
|
|
||||||
|
|
||||||
fill_in 'q', with: litteraire_user.email
|
|
||||||
find('.fr-search-bar .fr-btn').click
|
|
||||||
expect(page).to have_text('1 dossier trouvé')
|
|
||||||
|
|
||||||
## and the result is clickable
|
|
||||||
click_on litteraire_user.email
|
|
||||||
expect(page).to have_current_path(instructeur_dossier_path(procedure, litteraire_user.dossiers.first))
|
|
||||||
|
|
||||||
# follow the dossier
|
|
||||||
click_on 'Suivre le dossier'
|
|
||||||
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# the scientifiques instructeurs only manage the scientifiques dossiers
|
|
||||||
register_instructeur_and_log_in(marie.email)
|
|
||||||
click_on procedure.libelle
|
|
||||||
expect(page).not_to have_text(litteraire_user.email)
|
|
||||||
expect(page).to have_text(scientifique_user.email)
|
|
||||||
|
|
||||||
# follow the dossier
|
|
||||||
click_on scientifique_user.email
|
|
||||||
click_on 'Suivre le dossier'
|
|
||||||
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# litteraire_user change its dossier
|
|
||||||
visit new_user_session_path
|
|
||||||
sign_in_with litteraire_user.email, password
|
|
||||||
|
|
||||||
click_on litteraire_user.dossiers.first.id.to_s
|
|
||||||
click_on 'Modifier mon dossier'
|
|
||||||
|
|
||||||
fill_in litteraire_user.dossiers.first.champs_public.first.libelle, with: 'some value'
|
|
||||||
wait_for_autosave(false)
|
|
||||||
|
|
||||||
click_on 'Déposer les modifications'
|
|
||||||
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# the litteraires instructeurs should have a notification
|
|
||||||
visit new_user_session_path
|
|
||||||
sign_in_with victor.user.email, password
|
|
||||||
|
|
||||||
## on the procedures list
|
|
||||||
expect(page).to have_current_path(instructeur_procedures_path)
|
|
||||||
expect(find('.procedure-stats')).to have_css('span.notifications')
|
|
||||||
|
|
||||||
## on the dossiers list
|
|
||||||
click_on procedure.libelle
|
|
||||||
expect(page).to have_current_path(instructeur_procedure_path(procedure))
|
|
||||||
expect(find('.tabs')).to have_css('span.notifications')
|
|
||||||
|
|
||||||
## on the dossier itself
|
|
||||||
click_on 'suivi'
|
|
||||||
click_on litteraire_user.email
|
|
||||||
expect(page).to have_current_path(instructeur_dossier_path(procedure, litteraire_user.dossiers.first))
|
|
||||||
expect(page).to have_text('Annotations privées')
|
|
||||||
expect(find('.tabs')).to have_css('span.notifications')
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# the scientifiques instructeurs should not have a notification
|
|
||||||
visit new_user_session_path
|
|
||||||
sign_in_with marie.user.email, password
|
|
||||||
|
|
||||||
expect(page).to have_current_path(instructeur_procedures_path)
|
|
||||||
expect(find('.procedure-stats')).not_to have_css('span.notifications')
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# the instructeurs who belong to scientifique AND litteraire groups manage scientifique and litterraire dossiers
|
|
||||||
register_instructeur_and_log_in(superwoman.email)
|
|
||||||
visit instructeur_procedure_path(procedure, params: { statut: 'tous' })
|
|
||||||
expect(page).to have_text(litteraire_user.email)
|
|
||||||
expect(page).to have_text(scientifique_user.email)
|
|
||||||
|
|
||||||
# follow the dossier
|
|
||||||
click_on scientifique_user.email
|
|
||||||
click_on 'Suivre le dossier'
|
|
||||||
|
|
||||||
visit instructeur_procedure_path(procedure, params: { statut: 'tous' })
|
|
||||||
click_on litteraire_user.email
|
|
||||||
click_on 'Suivre le dossier'
|
|
||||||
log_out
|
|
||||||
|
|
||||||
# scientifique_user updates its group
|
|
||||||
user_update_group(scientifique_user, 'littéraire')
|
|
||||||
|
|
||||||
# the instructeurs who belong to scientifique AND litteraire groups should have a notification
|
|
||||||
visit new_user_session_path
|
|
||||||
sign_in_with superwoman.user.email, password
|
|
||||||
|
|
||||||
expect(page).to have_current_path(instructeur_procedures_path)
|
|
||||||
expect(find('.procedure-stats')).to have_css('span.notifications')
|
|
||||||
end
|
|
||||||
|
|
||||||
def publish_procedure(procedure)
|
|
||||||
click_on procedure.libelle
|
|
||||||
find('#publish-procedure-link').click
|
|
||||||
fill_in 'lien_site_web', with: 'http://some.website'
|
|
||||||
click_on 'Publier'
|
|
||||||
|
|
||||||
expect(page).to have_text('Démarche publiée')
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_send_dossier(user, groupe)
|
|
||||||
login_as user, scope: :user
|
|
||||||
visit commencer_path(path: procedure.reload.path)
|
|
||||||
click_on 'Commencer la démarche'
|
|
||||||
|
|
||||||
choose 'Monsieur'
|
|
||||||
fill_in 'individual_nom', with: 'Nom'
|
|
||||||
fill_in 'individual_prenom', with: 'Prenom'
|
|
||||||
click_button('Continuer')
|
|
||||||
|
|
||||||
select(groupe, from: 'dossier_groupe_instructeur_id')
|
|
||||||
wait_for_autosave
|
|
||||||
|
|
||||||
click_on 'Déposer le dossier'
|
|
||||||
expect(page).to have_text('Merci')
|
|
||||||
|
|
||||||
log_out
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_update_group(user, new_group)
|
|
||||||
login_as user, scope: :user
|
|
||||||
visit dossiers_path
|
|
||||||
click_on user.dossiers.first.id.to_s
|
|
||||||
click_on "Modifier mon dossier"
|
|
||||||
expect(page).to have_selector("option", text: "scientifique")
|
|
||||||
expect(page).not_to have_selector("option", text: "Groupe inactif")
|
|
||||||
|
|
||||||
select(new_group, from: 'dossier_groupe_instructeur_id')
|
|
||||||
wait_for_autosave(false)
|
|
||||||
|
|
||||||
expect(page).to have_text(new_group)
|
|
||||||
|
|
||||||
click_on 'Déposer les modifications'
|
|
||||||
|
|
||||||
log_out
|
|
||||||
end
|
|
||||||
|
|
||||||
def register_instructeur_and_log_in(email)
|
|
||||||
confirmation_email = emails_sent_to(email)
|
|
||||||
.find { |m| m.subject == 'Activez votre compte instructeur' }
|
|
||||||
token_params = confirmation_email.body.match(/token=[^"]+/)
|
|
||||||
|
|
||||||
visit "users/activate?#{token_params}"
|
|
||||||
fill_in :user_password, with: password
|
|
||||||
click_button 'Définir le mot de passe'
|
|
||||||
|
|
||||||
expect(page).to have_text('Mot de passe enregistré')
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -10,28 +10,60 @@ describe 'The routing with rules', js: true do
|
||||||
p.draft_revision.add_type_de_champ(
|
p.draft_revision.add_type_de_champ(
|
||||||
type_champ: :drop_down_list,
|
type_champ: :drop_down_list,
|
||||||
libelle: 'Spécialité',
|
libelle: 'Spécialité',
|
||||||
options: { "drop_down_other" => "0", "drop_down_options" => ["", "littéraire", "scientifique"] }
|
options: { "drop_down_other" => "0", "drop_down_options" => ["", "littéraire", "scientifique", "artistique"] }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
let(:administrateur) { create(:administrateur, procedures: [procedure]) }
|
let(:administrateur) { create(:administrateur, procedures: [procedure]) }
|
||||||
let(:scientifique_user) { create(:user, password: password) }
|
let(:scientifique_user) { create(:user, password: password) }
|
||||||
let(:litteraire_user) { create(:user, password: password) }
|
let(:litteraire_user) { create(:user, password: password) }
|
||||||
|
let(:artistique_user) { create(:user, password: password) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Flipper.enable(:routing_rules, procedure)
|
Flipper.enable(:routing_rules, procedure)
|
||||||
procedure.defaut_groupe_instructeur.instructeurs << administrateur.instructeur
|
procedure.defaut_groupe_instructeur.instructeurs << administrateur.instructeur
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'works' do
|
scenario 'Routage à partir d’un champ' do
|
||||||
login_as administrateur.user, scope: :user
|
steps_to_routing_configuration
|
||||||
visit admin_procedure_path(procedure.id)
|
|
||||||
find('#groupe-instructeurs').click
|
|
||||||
|
|
||||||
# add littéraire groupe
|
choose('À partir d’un champ', allow_label_click: true)
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'littéraire'
|
click_on 'Continuer'
|
||||||
click_on 'Ajouter le groupe'
|
|
||||||
expect(page).to have_text('Le groupe d’instructeurs « littéraire » a été créé et le routage a été activé.')
|
expect(page).to have_text('Routage à partir d’un champ')
|
||||||
|
|
||||||
|
choose('Spécialité', allow_label_click: true)
|
||||||
|
click_on 'Créer les groupes'
|
||||||
|
|
||||||
|
expect(page).to have_text('Gestion des groupes')
|
||||||
|
expect(page).to have_text('3 groupes')
|
||||||
|
expect(page).not_to have_text('À configurer')
|
||||||
|
|
||||||
|
click_on 'littéraire'
|
||||||
|
expect(page).to have_select("targeted_champ", selected: "Spécialité")
|
||||||
|
expect(page).to have_select("value", selected: "littéraire")
|
||||||
|
|
||||||
|
click_on '3 groupes'
|
||||||
|
click_on 'scientifique'
|
||||||
|
|
||||||
|
expect(page).to have_select("targeted_champ", selected: "Spécialité")
|
||||||
|
expect(page).to have_select("value", selected: "scientifique")
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Routage personnalisé' do
|
||||||
|
steps_to_routing_configuration
|
||||||
|
|
||||||
|
choose('Avancé', allow_label_click: true)
|
||||||
|
click_on 'Continuer'
|
||||||
|
|
||||||
|
expect(page).to have_text('Gestion des groupes')
|
||||||
|
|
||||||
|
# update defaut groupe
|
||||||
|
click_on 'défaut'
|
||||||
|
expect(page).to have_text('Paramètres principaux')
|
||||||
|
fill_in 'Nom du groupe', with: 'littéraire'
|
||||||
|
click_on 'Renommer'
|
||||||
|
expect(page).to have_text('Le nom est à présent « littéraire ». ')
|
||||||
|
|
||||||
# add victor to littéraire groupe
|
# add victor to littéraire groupe
|
||||||
fill_in 'Emails', with: 'victor@inst.com'
|
fill_in 'Emails', with: 'victor@inst.com'
|
||||||
|
@ -48,17 +80,18 @@ describe 'The routing with rules', js: true do
|
||||||
superwoman = User.find_by(email: 'superwoman@inst.com').instructeur
|
superwoman = User.find_by(email: 'superwoman@inst.com').instructeur
|
||||||
|
|
||||||
# add inactive groupe
|
# add inactive groupe
|
||||||
click_on 'Groupes d’instructeurs'
|
click_on 'Ajout de groupes'
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'non visible car inactif'
|
fill_in 'Nouveau groupe', with: 'non visible car inactif'
|
||||||
click_on 'Ajouter le groupe'
|
click_on 'Ajouter'
|
||||||
check "Groupe inactif"
|
expect(page).to have_text('Le groupe d’instructeurs « non visible car inactif » a été créé. ')
|
||||||
click_on 'Modifier'
|
check("Groupe inactif", allow_label_click: true)
|
||||||
|
|
||||||
# add scientifique groupe
|
# # add scientifique groupe
|
||||||
click_on 'Groupes d’instructeurs'
|
click_on '3 groupes'
|
||||||
fill_in 'Ajouter un nom de groupe', with: 'scientifique'
|
click_on 'défaut bis'
|
||||||
click_on 'Ajouter le groupe'
|
fill_in 'Nom du groupe', with: 'scientifique'
|
||||||
expect(page).to have_text('Le groupe d’instructeurs « scientifique » a été créé.')
|
click_on 'Renommer'
|
||||||
|
expect(page).to have_text('Le nom est à présent « scientifique ». ')
|
||||||
|
|
||||||
# add marie to scientifique groupe
|
# add marie to scientifique groupe
|
||||||
fill_in 'Emails', with: 'marie@inst.com'
|
fill_in 'Emails', with: 'marie@inst.com'
|
||||||
|
@ -73,30 +106,33 @@ describe 'The routing with rules', js: true do
|
||||||
expect(page).to have_text("L’instructeur superwoman@inst.com a été affecté")
|
expect(page).to have_text("L’instructeur superwoman@inst.com a été affecté")
|
||||||
|
|
||||||
# add routing rules
|
# add routing rules
|
||||||
click_on 'Groupes d’instructeurs'
|
within('.target') { select('Spécialité') }
|
||||||
|
within('.value') { select('scientifique') }
|
||||||
|
|
||||||
h = procedure.groupe_instructeurs.index_by(&:label).transform_values(&:id)
|
click_on '3 groupes'
|
||||||
|
|
||||||
within(".gi-#{h['scientifique']}") do
|
click_on 'littéraire'
|
||||||
within('.target') { select('Spécialité') }
|
|
||||||
within('.value') { select('scientifique') }
|
|
||||||
end
|
|
||||||
|
|
||||||
within(".gi-#{h['littéraire']}") do
|
within('.target') { select('Spécialité') }
|
||||||
within('.target') { select('Spécialité') }
|
within('.value') { select('littéraire') }
|
||||||
within('.value') { select('littéraire') }
|
|
||||||
end
|
|
||||||
|
|
||||||
not_defauts = procedure.groupe_instructeurs.filter { |gi| ['littéraire', 'scientifique'].include?(gi.label) }
|
procedure.groupe_instructeurs.where(closed: false).each { |gi| wait_until { gi.reload.routing_rule.present? } }
|
||||||
not_defauts.each { |gi| wait_until { gi.reload.routing_rule.present? } }
|
|
||||||
|
# add a group without routing rules
|
||||||
|
click_on 'Ajout de groupes'
|
||||||
|
fill_in 'Nouveau groupe', with: 'artistique'
|
||||||
|
click_on 'Ajouter'
|
||||||
|
expect(page).to have_text('Le groupe d’instructeurs « artistique » a été créé. ')
|
||||||
|
expect(procedure.groupe_instructeurs.count).to eq(4)
|
||||||
|
|
||||||
# publish
|
# publish
|
||||||
publish_procedure(procedure)
|
publish_procedure(procedure)
|
||||||
log_out
|
log_out
|
||||||
|
|
||||||
# 2 users fill a dossier in each group
|
# 3 users fill a dossier in each group
|
||||||
user_send_dossier(scientifique_user, 'scientifique')
|
user_send_dossier(scientifique_user, 'scientifique')
|
||||||
user_send_dossier(litteraire_user, 'littéraire')
|
user_send_dossier(litteraire_user, 'littéraire')
|
||||||
|
user_send_dossier(artistique_user, 'artistique')
|
||||||
|
|
||||||
# the litteraires instructeurs only manage the litteraires dossiers
|
# the litteraires instructeurs only manage the litteraires dossiers
|
||||||
register_instructeur_and_log_in(victor.email)
|
register_instructeur_and_log_in(victor.email)
|
||||||
|
@ -179,7 +215,7 @@ describe 'The routing with rules', js: true do
|
||||||
expect(find('.procedure-stats')).not_to have_css('span.notifications')
|
expect(find('.procedure-stats')).not_to have_css('span.notifications')
|
||||||
log_out
|
log_out
|
||||||
|
|
||||||
# the instructeurs who belong to scientifique AND litteraire groups manage scientifique and litterraire dossiers
|
# the instructeurs who belong to scientifique AND litteraire groups manage scientifique and litteraire dossiers
|
||||||
register_instructeur_and_log_in(superwoman.email)
|
register_instructeur_and_log_in(superwoman.email)
|
||||||
visit instructeur_procedure_path(procedure, params: { statut: 'tous' })
|
visit instructeur_procedure_path(procedure, params: { statut: 'tous' })
|
||||||
expect(page).to have_text(litteraire_user.email)
|
expect(page).to have_text(litteraire_user.email)
|
||||||
|
@ -263,4 +299,15 @@ describe 'The routing with rules', js: true do
|
||||||
|
|
||||||
expect(page).to have_text('Mot de passe enregistré')
|
expect(page).to have_text('Mot de passe enregistré')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def steps_to_routing_configuration
|
||||||
|
login_as administrateur.user, scope: :user
|
||||||
|
visit admin_procedure_path(procedure.id)
|
||||||
|
find('#groupe-instructeurs').click
|
||||||
|
|
||||||
|
click_on 'Options'
|
||||||
|
expect(page).to have_text('Options concernant l’instruction')
|
||||||
|
click_on 'Configurer le routage'
|
||||||
|
expect(page).to have_text('Choix du type de routage')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue