From f945c02c3cd7d09dfc95d8f9ab376663e874ea15 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 15 Nov 2023 17:44:46 +0100 Subject: [PATCH 1/2] feat(conditional): add exclude operator --- .../conditions/conditions_component.rb | 3 +- app/models/groupe_instructeur.rb | 2 +- app/models/logic.rb | 4 ++- app/models/logic/exclude_operator.rb | 3 ++ config/locales/models/logic/fr.yml | 1 + spec/models/logic/exclude_operator_spec.rb | 29 +++++++++++++++++++ 6 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 app/models/logic/exclude_operator.rb create mode 100644 spec/models/logic/exclude_operator_spec.rb diff --git a/app/components/conditions/conditions_component.rb b/app/components/conditions/conditions_component.rb index 833e2c89d..7cfd3f22b 100644 --- a/app/components/conditions/conditions_component.rb +++ b/app/components/conditions/conditions_component.rb @@ -99,7 +99,8 @@ class Conditions::ConditionsComponent < ApplicationComponent ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:enums) [ - [t(IncludeOperator.name, scope: 'logic.operators'), IncludeOperator.name] + [t(IncludeOperator.name, scope: 'logic.operators'), IncludeOperator.name], + [t(ExcludeOperator.name, scope: 'logic.operators'), ExcludeOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:number) [Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq] diff --git a/app/models/groupe_instructeur.rb b/app/models/groupe_instructeur.rb index e9b67ac6c..f7ecf059d 100644 --- a/app/models/groupe_instructeur.rb +++ b/app/models/groupe_instructeur.rb @@ -92,7 +92,7 @@ class GroupeInstructeur < ApplicationRecord end def valid_rule_line?(rule) - ([rule.left, rule, rule.right] in [ChampValue, (LessThan | LessThanEq | Eq | NotEq | GreaterThanEq | GreaterThan | IncludeOperator), Constant]) && routing_rule_matches_tdc?(rule) + ([rule.left, rule, rule.right] in [ChampValue, (LessThan | LessThanEq | Eq | NotEq | GreaterThanEq | GreaterThan | IncludeOperator | ExcludeOperator), Constant]) && routing_rule_matches_tdc?(rule) end def non_unique_rule? diff --git a/app/models/logic.rb b/app/models/logic.rb index 5c3f1c25c..7c4c7ba56 100644 --- a/app/models/logic.rb +++ b/app/models/logic.rb @@ -8,7 +8,7 @@ module Logic end def self.class_from_name(name) - [ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, IncludeOperator, And, Or] + [ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, IncludeOperator, ExcludeOperator, And, Or] .find { |c| c.name == name } end @@ -88,6 +88,8 @@ module Logic def ds_include(left, right) = Logic::IncludeOperator.new(left, right) + def ds_exclude(left, right) = Logic::ExcludeOperator.new(left, right) + def constant(value) = Logic::Constant.new(value) def champ_value(stable_id) = Logic::ChampValue.new(stable_id) diff --git a/app/models/logic/exclude_operator.rb b/app/models/logic/exclude_operator.rb new file mode 100644 index 000000000..8addb7d0a --- /dev/null +++ b/app/models/logic/exclude_operator.rb @@ -0,0 +1,3 @@ +class Logic::ExcludeOperator < Logic::IncludeOperator + def operation = :exclude? +end diff --git a/config/locales/models/logic/fr.yml b/config/locales/models/logic/fr.yml index 7f3045c3d..5d5075cc1 100644 --- a/config/locales/models/logic/fr.yml +++ b/config/locales/models/logic/fr.yml @@ -14,3 +14,4 @@ fr: 'Logic::Or': Ou 'Logic::NotEq': N’est pas 'Logic::IncludeOperator': Contient + 'Logic::ExcludeOperator': Ne contient pas diff --git a/spec/models/logic/exclude_operator_spec.rb b/spec/models/logic/exclude_operator_spec.rb new file mode 100644 index 000000000..b4c1248b7 --- /dev/null +++ b/spec/models/logic/exclude_operator_spec.rb @@ -0,0 +1,29 @@ +describe Logic::ExcludeOperator do + include Logic + + let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') } + + describe '#compute' do + it { expect(ds_exclude(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(false) } + it { expect(ds_exclude(champ_value(champ.stable_id), constant('something else')).compute([champ])).to be(true) } + end + + describe '#errors' do + it { expect(ds_exclude(champ_value(champ.stable_id), constant('val1')).errors([champ.type_de_champ])).to be_empty } + it do + expected = { + right: constant('something else'), + stable_id: champ.stable_id, + type: :not_included + } + + expect(ds_exclude(champ_value(champ.stable_id), constant('something else')).errors([champ.type_de_champ])).to eq([expected]) + end + + it { expect(ds_exclude(constant(1), constant('val1')).errors([])).to eq([{ type: :required_list }]) } + end + + describe '#==' do + it { expect(ds_include(champ_value(champ.stable_id), constant('val1'))).to eq(ds_include(champ_value(champ.stable_id), constant('val1'))) } + end +end From a54d55486c8e6210a82caf5df7fc90e417f072c6 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Wed, 22 Nov 2023 12:04:25 +0100 Subject: [PATCH 2/2] chore(routing): update routing_rule validation --- app/models/groupe_instructeur.rb | 2 +- spec/models/routing_engine_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/groupe_instructeur.rb b/app/models/groupe_instructeur.rb index f7ecf059d..524d9e9c8 100644 --- a/app/models/groupe_instructeur.rb +++ b/app/models/groupe_instructeur.rb @@ -92,7 +92,7 @@ class GroupeInstructeur < ApplicationRecord end def valid_rule_line?(rule) - ([rule.left, rule, rule.right] in [ChampValue, (LessThan | LessThanEq | Eq | NotEq | GreaterThanEq | GreaterThan | IncludeOperator | ExcludeOperator), Constant]) && routing_rule_matches_tdc?(rule) + !rule.is_a?(EmptyOperator) && routing_rule_matches_tdc?(rule) end def non_unique_rule? diff --git a/spec/models/routing_engine_spec.rb b/spec/models/routing_engine_spec.rb index 36ea5bc63..4692638d7 100644 --- a/spec/models/routing_engine_spec.rb +++ b/spec/models/routing_engine_spec.rb @@ -28,7 +28,7 @@ describe RoutingEngine, type: :model do context 'without any matching rules' do before do procedure.groupe_instructeurs.each do |gi| - gi.update(routing_rule: ds_eq(constant(false), constant(false))) + gi.update(routing_rule: ds_eq(constant(false), constant(true))) end end