diff --git a/app/validators/types_de_champ/condition_validator.rb b/app/validators/types_de_champ/condition_validator.rb index 65e1e887ae1..86e23ff62d8 100644 --- a/app/validators/types_de_champ/condition_validator.rb +++ b/app/validators/types_de_champ/condition_validator.rb @@ -1,24 +1,34 @@ class TypesDeChamp::ConditionValidator < ActiveModel::EachValidator - def validate_each(procedure, attribute, types_de_champ) - return if types_de_champ.empty? + # condition are valid when + # tdc.condition.left is present in upper tdcs + # in case of types_de_champ_private, we should include types_de_champ_publics too + def validate_each(procedure, collection, tdcs) + return if tdcs.empty? - tdcs = if attribute == :draft_types_de_champ_private - procedure.draft_revision.types_de_champ_for - else - procedure.draft_revision.types_de_champ_for(scope: :public) - end - - tdcs.each_with_index do |tdc, i| + tdcs = tdcs_with_children(procedure, tdcs) + tdcs.each_with_index do |tdc, tdc_index| next unless tdc.condition? - errors = tdc.condition.errors(tdcs.take(i)) + upper_tdcs = [] + if collection == :draft_types_de_champ_private # in case of private tdc validation, we must include public tdcs + upper_tdcs += tdcs_with_children(procedure, procedure.draft_types_de_champ_public) + end + upper_tdcs += tdcs.take(tdc_index) # we take all upper_tdcs of current tdcs + + errors = tdc.condition.errors(upper_tdcs) next if errors.blank? procedure.errors.add( - attribute, - procedure.errors.generate_message(attribute, :invalid_condition, { value: tdc.libelle }), + collection, + procedure.errors.generate_message(collection, :invalid_condition, { value: tdc.libelle }), type_de_champ: tdc ) end end + + # find children in repetitions + def tdcs_with_children(procedure, tdcs) + tdcs.to_a + .flat_map { _1.repetition? ? procedure.draft_revision.children_of(_1) : _1 } + end end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 0fa94a425d1..0b8b3f4ed10 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -441,6 +441,33 @@ end end + context 'when condition on champ private use public champ having a position higher than the champ private' do + include Logic + + let(:types_de_champ_public) do + [ + { type: :decimal_number, stable_id: 1 }, + { type: :decimal_number, stable_id: 2 } + ] + end + + let(:types_de_champ_private) do + [ + { type: :text, condition: ds_eq(champ_value(2), constant(2)), stable_id: 3 } + ] + end + + it 'validate without context' do + procedure.validate + expect(procedure.errors.full_messages_for(:draft_types_de_champ_private)).to be_empty + end + + it 'validate allows condition' do + procedure.validate(:types_de_champ_private_editor) + expect(procedure.errors.full_messages_for(:draft_types_de_champ_private)).to be_empty + end + end + context 'when condition on champ public use private champ' do include Logic let(:types_de_champ_public) { [{ type: :text, libelle: 'condition', condition: ds_eq(champ_value(1), constant(2)), stable_id: 2 }] }