Merge pull request #9423 from demarches-simplifiees/can-route-with-not-equals-routing-rules

ETQ admin je peux router avec des règles dont l'opérateur est "n'est pas"
This commit is contained in:
Eric Leroy-Terquem 2023-09-06 07:26:56 +00:00 committed by GitHub
commit 0c004fd4e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 26 deletions

View file

@ -17,6 +17,10 @@ class Procedure::OneGroupeManagementComponent < ApplicationComponent
@groupe_instructeur.routing_rule&.right || empty @groupe_instructeur.routing_rule&.right || empty
end end
def operator_name
@groupe_instructeur.routing_rule&.class&.name || empty
end
def targeted_champ_tag def targeted_champ_tag
select_tag( select_tag(
'targeted_champ', 'targeted_champ',
@ -39,6 +43,21 @@ class Procedure::OneGroupeManagementComponent < ApplicationComponent
.map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] } .map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] }
end end
def operator_tag
select_tag('operator_name',
options_for_select(
options_for_operator_tag,
selected: operator_name
),
class: 'fr-select')
end
def options_for_operator_tag
[Eq, NotEq]
.map(&:name)
.map { |name| [t(name, scope: 'logic.operators'), name] }
end
def value_tag def value_tag
select_tag( select_tag(
'value', 'value',

View file

@ -40,7 +40,8 @@
.fr-mr-2w.no-wrap si le champ .fr-mr-2w.no-wrap si le champ
.target.fr-mr-2w .target.fr-mr-2w
= targeted_champ_tag = targeted_champ_tag
.operator.fr-mr-2w.no-wrap est égal à .operator.fr-mr-2w.no-wrap
= operator_tag
.value .value
= value_tag = value_tag
.fr-hint-text .fr-hint-text

View file

@ -9,7 +9,13 @@ module Administrateurs
right = targeted_champ_changed? ? empty : value right = targeted_champ_changed? ? empty : value
groupe_instructeur.update!(routing_rule: ds_eq(left, right)) new_routing_rule = case operator_name
when Eq.name
ds_eq(left, right)
when NotEq.name
ds_not_eq(left, right)
end
groupe_instructeur.update!(routing_rule: new_routing_rule)
end end
def update_defaut_groupe_instructeur def update_defaut_groupe_instructeur
@ -27,6 +33,10 @@ module Administrateurs
Logic.from_json(params[:targeted_champ]) Logic.from_json(params[:targeted_champ])
end end
def operator_name
params[:operator_name]
end
def value def value
Logic.from_json(params[:value]) Logic.from_json(params[:value])
end end

View file

@ -73,9 +73,12 @@ class GroupeInstructeur < ApplicationRecord
end end
def invalid_rule? def invalid_rule?
rule = routing_rule !valid_rule?
return true if !(rule.is_a?(Logic::Eq) && rule.left.is_a?(Logic::ChampValue) && rule.right.is_a?(Logic::Constant)) end
return true if !routing_rule_matches_tdc?
def valid_rule?
return false if routing_rule.nil?
([routing_rule.left, routing_rule, routing_rule.right] in [ChampValue, Eq | NotEq, Constant]) && routing_rule_matches_tdc?
end end
def non_unique_rule? def non_unique_rule?

View file

@ -11,40 +11,82 @@ describe Administrateurs::RoutingController, type: :controller do
{ {
procedure_id: procedure.id, procedure_id: procedure.id,
targeted_champ: champ_value(drop_down_tdc.stable_id).to_json, targeted_champ: champ_value(drop_down_tdc.stable_id).to_json,
operator_name: operator_name,
value: empty.to_json, value: empty.to_json,
groupe_instructeur_id: gi_2.id groupe_instructeur_id: gi_2.id
} }
end end
before do context 'with Eq operator' do
post :update, params: params, format: :turbo_stream let(:operator_name) { Logic::Eq.name }
end
it do
expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), empty))
end
context '#update value' do
let(:value_updated_params) { params.merge(value: constant('Lyon').to_json) }
before do before do
post :update, params: value_updated_params, format: :turbo_stream post :update, params: params, format: :turbo_stream
end end
it do it do
expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon'))) expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), empty))
end end
context 'targeted champ changed' do context '#update value' do
let(:last_tdc) { procedure.draft_revision.types_de_champ.last } let(:value_updated_params) { params.merge(value: constant('Lyon').to_json) }
before do before do
targeted_champ_updated_params = value_updated_params.merge(targeted_champ: champ_value(last_tdc.stable_id).to_json) post :update, params: value_updated_params, format: :turbo_stream
post :update, params: targeted_champ_updated_params, format: :turbo_stream
end end
it do it do
expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(last_tdc.stable_id), empty)) expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
end
context 'targeted champ changed' do
let(:last_tdc) { procedure.draft_revision.types_de_champ.last }
before do
targeted_champ_updated_params = value_updated_params.merge(targeted_champ: champ_value(last_tdc.stable_id).to_json)
post :update, params: targeted_champ_updated_params, format: :turbo_stream
end
it do
expect(gi_2.reload.routing_rule).to eq(ds_eq(champ_value(last_tdc.stable_id), empty))
end
end
end
end
context 'with NotEq operator' do
let(:operator_name) { Logic::NotEq.name }
before do
post :update, params: params, format: :turbo_stream
end
it do
expect(gi_2.reload.routing_rule).to eq(ds_not_eq(champ_value(drop_down_tdc.stable_id), empty))
end
context '#update value' do
let(:value_updated_params) { params.merge(value: constant('Lyon').to_json) }
before do
post :update, params: value_updated_params, format: :turbo_stream
end
it do
expect(gi_2.reload.routing_rule).to eq(ds_not_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
end
context 'targeted champ changed' do
let(:last_tdc) { procedure.draft_revision.types_de_champ.last }
before do
targeted_champ_updated_params = value_updated_params.merge(targeted_champ: champ_value(last_tdc.stable_id).to_json)
post :update, params: targeted_champ_updated_params, format: :turbo_stream
end
it do
expect(gi_2.reload.routing_rule).to eq(ds_not_eq(champ_value(last_tdc.stable_id), empty))
end
end end
end end
end end

View file

@ -4,7 +4,7 @@ describe RoutingEngine, type: :model do
describe '.compute' do describe '.compute' do
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.create(label: 'a second group') }
subject do subject do
RoutingEngine.compute(dossier) RoutingEngine.compute(dossier)
@ -15,7 +15,6 @@ describe RoutingEngine, type: :model do
let(:procedure) do let(:procedure) do
create(:procedure, create(:procedure,
types_de_champ_public: [{ type: :drop_down_list, libelle: 'Votre ville', options: ['Paris', 'Lyon', 'Marseille'] }]).tap do |p| types_de_champ_public: [{ type: :drop_down_list, libelle: 'Votre ville', options: ['Paris', 'Lyon', 'Marseille'] }]).tap do |p|
p.groupe_instructeurs.create(label: 'a second group')
p.groupe_instructeurs.create(label: 'a third group') p.groupe_instructeurs.create(label: 'a third group')
end end
end end
@ -29,7 +28,7 @@ describe RoutingEngine, type: :model do
context 'without any matching rules' do context 'without any matching rules' do
before do before do
procedure.groupe_instructeurs.each do |gi| procedure.groupe_instructeurs.each do |gi|
gi.update(routing_rule: constant(false)) gi.update(routing_rule: ds_eq(constant(false), constant(false)))
end end
end end
@ -60,12 +59,23 @@ describe RoutingEngine, type: :model do
it { is_expected.to eq(defaut_groupe) } it { is_expected.to eq(defaut_groupe) }
end end
context 'with a non equals rule' do
before do
gi_2.update(routing_rule: ds_not_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
dossier.champs.first.update(value: 'Paris')
end
it do
is_expected.not_to eq(defaut_groupe)
is_expected.to eq(gi_2)
end
end
end end
context 'with a departements type de champ' do context 'with a departements type de champ' do
let(:procedure) do let(:procedure) do
create(:procedure, types_de_champ_public: [{ type: :departements }]).tap do |p| create(:procedure, types_de_champ_public: [{ type: :departements }]).tap do |p|
p.groupe_instructeurs.create(label: 'a second group')
p.groupe_instructeurs.create(label: 'a third group') p.groupe_instructeurs.create(label: 'a third group')
end end
end end
@ -81,5 +91,31 @@ describe RoutingEngine, type: :model do
it { is_expected.to eq(gi_2) } it { is_expected.to eq(gi_2) }
end end
end end
context 'routing rules priorities' do
let(:procedure) do
create(:procedure,
types_de_champ_public: [{ type: :drop_down_list, libelle: 'Ville', options: ['Paris', 'Lyon', 'Marseille'] }]).tap do |p|
p.groupe_instructeurs.create(label: 'c')
end
end
let(:drop_down_tdc) { procedure.draft_revision.types_de_champ.first }
let!(:gi_3) { procedure.groupe_instructeurs.find_by(label: 'c') }
context 'not eq rule coming first' do
before do
defaut_groupe.update(label: 'a')
gi_2.update(label: 'b', routing_rule: ds_not_eq(champ_value(drop_down_tdc.stable_id), constant('Lyon')))
gi_3.update(routing_rule: ds_eq(champ_value(drop_down_tdc.stable_id), constant('Marseille')))
dossier.champs.first.update(value: 'Marseille')
end
it 'computes by groups label order' do
is_expected.to eq(gi_2)
end
end
end
end end
end end