Merge pull request #8774 from E-L-T/add-routing-to-groupe-instructeurs
Add routing rules to groupe instructeurs
This commit is contained in:
commit
b003fd8be8
24 changed files with 575 additions and 22 deletions
|
@ -1,7 +1,7 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
form.form > .conditionnel {
|
||||
.conditionnel {
|
||||
|
||||
.condition-error {
|
||||
background: $background-red;
|
||||
|
|
66
app/components/procedure/routing_rules_component.rb
Normal file
66
app/components/procedure/routing_rules_component.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
class Procedure::RoutingRulesComponent < ApplicationComponent
|
||||
include Logic
|
||||
|
||||
def initialize(revision:, groupe_instructeurs:)
|
||||
@revision = revision
|
||||
@groupe_instructeurs = groupe_instructeurs
|
||||
end
|
||||
|
||||
def rows
|
||||
@groupe_instructeurs.active.map do |gi|
|
||||
[gi.routing_rule&.left, gi.routing_rule&.right, gi]
|
||||
end
|
||||
end
|
||||
|
||||
def targeted_champ_tag(targeted_champ, row_index)
|
||||
select_tag(
|
||||
'targeted_champ',
|
||||
options_for_select(targeted_champs_for_select, selected: targeted_champ&.stable_id),
|
||||
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), selected: value),
|
||||
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, tdc.stable_id] }
|
||||
end
|
||||
|
||||
def available_values_for_select(targeted_champ)
|
||||
return [] if targeted_champ.nil?
|
||||
targeted_champ.options(@revision.types_de_champ_public)
|
||||
end
|
||||
|
||||
def values_for_select(targeted_champ)
|
||||
empty_target_for_select + available_values_for_select(targeted_champ)
|
||||
end
|
||||
|
||||
def input_id_for(name, row_index)
|
||||
"#{name}-#{row_index}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
fr:
|
||||
select: Sélectionner
|
||||
apply_routing_rules: Appliquer des règles de routage
|
||||
routing_rules_notice: |
|
||||
Ajoutez des règles de routage à partir de champs créés dans le formulaire.
|
||||
Si les mêmes règles de routage sont appliquées à plusieurs groupes,
|
||||
les dossiers seront routés vers le premier groupe affiché dans la liste.
|
|
@ -0,0 +1,26 @@
|
|||
.card#routing-rules
|
||||
.card-title
|
||||
= t('.apply_routing_rules')
|
||||
%p.notice
|
||||
= t('.routing_rules_notice')
|
||||
.conditionnel.mt-2.width-100
|
||||
%table.condition-table.mt-2.width-100
|
||||
%thead
|
||||
%tr
|
||||
%th.far-left
|
||||
%th.target Champ cible du routage
|
||||
%th.operator Opérateur
|
||||
%th.value Valeur
|
||||
%th.delete-column
|
||||
.conditionnel.mt-2.width-100
|
||||
- rows.each.with_index do |(targeted_champ, value, groupe_instructeur), row_index|
|
||||
= form_tag admin_procedure_routing_rules_path, method: :post, class: "form width-100 gi-#{groupe_instructeur.id}" do
|
||||
%table.condition-table.mt-2.width-100
|
||||
%tbody
|
||||
%tr{ data: { controller: 'autosave' } }
|
||||
%td.far-left Router vers « #{groupe_instructeur.label} » si
|
||||
%td.target= targeted_champ_tag(targeted_champ, row_index)
|
||||
%td.operator Est égal à
|
||||
%td.value= value_tag(targeted_champ, value, row_index)
|
||||
%td.delete-column
|
||||
= hidden_groupe_instructeur_tag(groupe_instructeur.id)
|
38
app/controllers/administrateurs/routing_controller.rb
Normal file
38
app/controllers/administrateurs/routing_controller.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Administrateurs
|
||||
class RoutingController < AdministrateurController
|
||||
include Logic
|
||||
|
||||
before_action :retrieve_procedure
|
||||
|
||||
def update
|
||||
left = champ_value(targeted_champ)
|
||||
right = parsed_value
|
||||
|
||||
@procedure.groupe_instructeurs.find(groupe_instructeur_id).update!(routing_rule: ds_eq(left, right))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def targeted_champ
|
||||
routing_params[:targeted_champ].to_i
|
||||
end
|
||||
|
||||
def value
|
||||
routing_params[:value]
|
||||
end
|
||||
|
||||
def parsed_value
|
||||
term = Logic.from_json(value) rescue nil
|
||||
|
||||
term.presence || constant(value)
|
||||
end
|
||||
|
||||
def groupe_instructeur_id
|
||||
routing_params[:groupe_instructeur_id]
|
||||
end
|
||||
|
||||
def routing_params
|
||||
params.permit(:targeted_champ, :value, :groupe_instructeur_id)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -455,6 +455,10 @@ module Users
|
|||
@dossier.assign_to_groupe_instructeur(groupe_instructeur_from_params)
|
||||
end
|
||||
|
||||
if @dossier.procedure.feature_enabled?(:routing_rules)
|
||||
RoutingEngine.compute(@dossier)
|
||||
end
|
||||
|
||||
if dossier.en_construction?
|
||||
errors += @dossier.check_mandatory_and_visible_champs
|
||||
end
|
||||
|
|
|
@ -667,11 +667,11 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
def show_groupe_instructeur_details?
|
||||
procedure.routing_enabled? && groupe_instructeur.present? && (!procedure.feature_enabled?(:procedure_routage_api) || !defaut_groupe_instructeur?)
|
||||
procedure.routing_enabled? && groupe_instructeur.present? && (!procedure.feature_enabled?(:procedure_routage_api) || !defaut_groupe_instructeur?) && !procedure.feature_enabled?(:routing_rules)
|
||||
end
|
||||
|
||||
def show_groupe_instructeur_selector?
|
||||
procedure.routing_enabled? && !procedure.feature_enabled?(:procedure_routage_api)
|
||||
procedure.routing_enabled? && !procedure.feature_enabled?(:procedure_routage_api) && !procedure.feature_enabled?(:routing_rules)
|
||||
end
|
||||
|
||||
def assign_to_groupe_instructeur(groupe_instructeur, author = nil)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# id :bigint not null, primary key
|
||||
# closed :boolean default(FALSE)
|
||||
# label :text not null
|
||||
# routing_rule :jsonb
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# procedure_id :bigint not null
|
||||
|
@ -80,4 +81,6 @@ class GroupeInstructeur < ApplicationRecord
|
|||
def toggle_routing
|
||||
procedure.update!(routing_enabled: procedure.groupe_instructeurs.active.many?)
|
||||
end
|
||||
|
||||
serialize :routing_rule, LogicSerializer
|
||||
end
|
||||
|
|
|
@ -207,7 +207,7 @@ class Procedure < ApplicationRecord
|
|||
has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy
|
||||
has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy
|
||||
|
||||
has_one :defaut_groupe_instructeur, -> { active.order(:label) }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
has_one :defaut_groupe_instructeur, -> { active.order(id: :asc) }, class_name: 'GroupeInstructeur', inverse_of: false
|
||||
|
||||
has_one_attached :logo
|
||||
has_one_attached :notice
|
||||
|
|
9
app/models/routing_engine.rb
Normal file
9
app/models/routing_engine.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module RoutingEngine
|
||||
def self.compute(dossier)
|
||||
matching_groupe = dossier.procedure.groupe_instructeurs.active.find do |gi|
|
||||
gi.routing_rule&.compute(dossier.champs)
|
||||
end
|
||||
matching_groupe ||= dossier.procedure.defaut_groupe_instructeur
|
||||
dossier.update!(groupe_instructeur: matching_groupe)
|
||||
end
|
||||
end
|
|
@ -141,21 +141,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
serialize :options, WithIndifferentAccess
|
||||
|
||||
class ConditionSerializer
|
||||
def self.load(condition)
|
||||
if condition.present?
|
||||
Logic.from_h(condition)
|
||||
end
|
||||
end
|
||||
|
||||
def self.dump(condition)
|
||||
if condition.present?
|
||||
condition.to_h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
serialize :condition, ConditionSerializer
|
||||
serialize :condition, LogicSerializer
|
||||
|
||||
after_initialize :set_dynamic_type
|
||||
after_create :populate_stable_id
|
||||
|
|
13
app/serializers/logic_serializer.rb
Normal file
13
app/serializers/logic_serializer.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
class LogicSerializer
|
||||
def self.load(logic)
|
||||
if logic.present?
|
||||
Logic.from_h(logic)
|
||||
end
|
||||
end
|
||||
|
||||
def self.dump(logic)
|
||||
if logic.present?
|
||||
logic.to_h
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
- if groupes_instructeurs.many?
|
||||
- if groupes_instructeurs.many? && !procedure.feature_enabled?(:routing_rules)
|
||||
.card
|
||||
= form_for procedure,
|
||||
url: { action: :update_routing_criteria_name },
|
||||
|
|
|
@ -25,3 +25,7 @@
|
|||
= 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,2 @@
|
|||
= turbo_stream.replace 'routing-rules', render(Procedure::RoutingRulesComponent.new(revision: @procedure.active_revision,
|
||||
groupe_instructeurs: @procedure.groupe_instructeurs))
|
|
@ -16,7 +16,8 @@ features = [
|
|||
:api_particulier,
|
||||
:dossier_pdf_vide,
|
||||
:hide_instructeur_email,
|
||||
:procedure_routage_api
|
||||
:procedure_routage_api,
|
||||
:routing_rules
|
||||
]
|
||||
|
||||
def database_exists?
|
||||
|
|
|
@ -506,6 +506,8 @@ Rails.application.routes.draw do
|
|||
delete :delete_row, on: :member
|
||||
end
|
||||
|
||||
patch :update, controller: 'routing', as: :routing_rules
|
||||
|
||||
put 'clone'
|
||||
put 'archive'
|
||||
get 'publication' => 'procedures#publication', as: :publication
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddRoutingColumnToGroupeInstructeur < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :groupe_instructeurs, :routing_rule, :jsonb
|
||||
end
|
||||
end
|
|
@ -585,6 +585,7 @@ ActiveRecord::Schema.define(version: 2023_03_22_150907) do
|
|||
t.datetime "created_at", null: false
|
||||
t.text "label", null: false
|
||||
t.bigint "procedure_id", null: false
|
||||
t.jsonb "routing_rule"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["closed", "procedure_id"], name: "index_groupe_instructeurs_on_closed_and_procedure_id"
|
||||
t.index ["procedure_id", "label"], name: "index_groupe_instructeurs_on_procedure_id_and_label", unique: true
|
||||
|
|
28
spec/controllers/administrateurs/routing_controller_spec.rb
Normal file
28
spec/controllers/administrateurs/routing_controller_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
describe Administrateurs::RoutingController, type: :controller do
|
||||
include Logic
|
||||
|
||||
before { sign_in(procedure.administrateurs.first.user) }
|
||||
|
||||
describe '#update' do
|
||||
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :drop_down_list, libelle: 'Votre ville', options: ['Paris', 'Lyon', 'Marseille'] }]) }
|
||||
let(:gi_2) { procedure.groupe_instructeurs.create(label: 'groupe 2') }
|
||||
let(:drop_down_tdc) { procedure.draft_revision.types_de_champ.first }
|
||||
let(:params) do
|
||||
{
|
||||
procedure_id: procedure.id,
|
||||
targeted_champ: drop_down_tdc.stable_id,
|
||||
value: 'Lyon',
|
||||
groupe_instructeur_id: gi_2.id
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(procedure.administrateurs.first.user)
|
||||
post :update, params: params, format: :turbo_stream
|
||||
end
|
||||
|
||||
it do
|
||||
expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -572,7 +572,7 @@ describe Instructeur, type: :model do
|
|||
let(:instructeur_2) { create(:instructeur) }
|
||||
let(:instructeur_3) { create(:instructeur) }
|
||||
let(:procedure) { create(:procedure, instructeurs: [instructeur_2, instructeur_3], procedure_expires_when_termine_enabled: true) }
|
||||
let(:gi_1) { procedure.groupe_instructeurs.first }
|
||||
let(:gi_1) { procedure.defaut_groupe_instructeur }
|
||||
let(:gi_2) { procedure.groupe_instructeurs.create(label: '2') }
|
||||
let(:gi_3) { procedure.groupe_instructeurs.create(label: '3') }
|
||||
|
||||
|
|
47
spec/models/routing_engine_spec.rb
Normal file
47
spec/models/routing_engine_spec.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
describe RoutingEngine, type: :model do
|
||||
include Logic
|
||||
|
||||
describe '.compute' do
|
||||
let(:procedure) do
|
||||
create(:procedure).tap do |p|
|
||||
p.groupe_instructeurs.create(label: 'a second group')
|
||||
p.groupe_instructeurs.create(label: 'a third group')
|
||||
end
|
||||
end
|
||||
|
||||
let(:dossier) { create(:dossier, procedure:) }
|
||||
let(:defaut_groupe) { procedure.defaut_groupe_instructeur }
|
||||
let(:gi_2) { procedure.groupe_instructeurs.find_by(label: 'a second group') }
|
||||
|
||||
subject do
|
||||
RoutingEngine.compute(dossier)
|
||||
dossier.groupe_instructeur
|
||||
end
|
||||
|
||||
context 'without any rules' do
|
||||
it { is_expected.to eq(defaut_groupe) }
|
||||
end
|
||||
|
||||
context 'without any matching rules' do
|
||||
before do
|
||||
procedure.groupe_instructeurs.each do |gi|
|
||||
gi.update(routing_rule: constant(false))
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to eq(defaut_groupe) }
|
||||
end
|
||||
|
||||
context 'with a matching rules' do
|
||||
before { gi_2.update(routing_rule: constant(true)) }
|
||||
|
||||
it { is_expected.to eq(gi_2) }
|
||||
end
|
||||
|
||||
context 'with a closed gi with a matching rules' do
|
||||
before { gi_2.update(routing_rule: constant(true), closed: true) }
|
||||
|
||||
it { is_expected.to eq(defaut_groupe) }
|
||||
end
|
||||
end
|
||||
end
|
48
spec/system/administrateurs/procedure_routing_spec.rb
Normal file
48
spec/system/administrateurs/procedure_routing_spec.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
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 'Router vers « a second group »'
|
||||
expect(page).not_to have_content 'Router vers « défaut »'
|
||||
end
|
||||
end
|
||||
end
|
262
spec/system/routing/rules_full_scenario_spec.rb
Normal file
262
spec/system/routing/rules_full_scenario_spec.rb
Normal file
|
@ -0,0 +1,262 @@
|
|||
describe 'The routing with rules', js: true do
|
||||
let(:password) { 'a very complicated password' }
|
||||
|
||||
let(:procedure) do
|
||||
create(:procedure, :with_service, :for_individual, :with_zone).tap do |p|
|
||||
p.draft_revision.add_type_de_champ(
|
||||
type_champ: :text,
|
||||
libelle: 'un premier champ text'
|
||||
)
|
||||
p.draft_revision.add_type_de_champ(
|
||||
type_champ: :drop_down_list,
|
||||
libelle: 'Spécialité',
|
||||
options: { "drop_down_other" => "0", "drop_down_options" => ["", "littéraire", "scientifique"] }
|
||||
)
|
||||
end
|
||||
end
|
||||
let(:administrateur) { create(:administrateur, procedures: [procedure]) }
|
||||
let(:scientifique_user) { create(:user, password: password) }
|
||||
let(:litteraire_user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
Flipper.enable(:routing_rules, procedure)
|
||||
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
|
||||
|
||||
# add inactive groupe
|
||||
click_on 'Groupes d’instructeurs'
|
||||
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é")
|
||||
|
||||
# add routing rules
|
||||
click_on 'Groupes d’instructeurs'
|
||||
|
||||
h = procedure.groupe_instructeurs.index_by(&:label).transform_values(&:id)
|
||||
|
||||
within(".gi-#{h['scientifique']}") do
|
||||
within('.target') { select('Spécialité') }
|
||||
within('.value') { select('scientifique') }
|
||||
end
|
||||
|
||||
within(".gi-#{h['littéraire']}") do
|
||||
within('.target') { select('Spécialité') }
|
||||
within('.value') { select('littéraire') }
|
||||
end
|
||||
|
||||
not_defauts = procedure.groupe_instructeurs.filter { |gi| ['littéraire', 'scientifique'].include?(gi.label) }
|
||||
not_defauts.each { |gi| wait_until { gi.reload.routing_rule.present? } }
|
||||
|
||||
# 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é')
|
||||
|
||||
# weird bug, capabary appends text instead of replaces it
|
||||
# see https://github.com/redux-form/redux-form/issues/686
|
||||
fill_in('q', with: litteraire_user.email, fill_options: { clear: :backspace })
|
||||
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)
|
||||
|
||||
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')
|
||||
|
||||
# the old system should not be present
|
||||
expect(page).not_to have_selector("#dossier_groupe_instructeur_id")
|
||||
|
||||
choose(groupe)
|
||||
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"
|
||||
|
||||
choose(new_group)
|
||||
wait_for_autosave(false)
|
||||
|
||||
expect(page).to have_text(new_group)
|
||||
|
||||
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
|
Loading…
Reference in a new issue