From a4e6423b0f7ab49764198ac94b2d5a90a1bde27d Mon Sep 17 00:00:00 2001 From: mfo Date: Wed, 24 Apr 2024 10:11:20 +0200 Subject: [PATCH] wip(procedure_revision.compare): includes transitions_rules diff --- app/models/procedure_revision.rb | 14 + app/models/procedure_revision_change.rb | 15 + spec/models/procedure_revision_spec.rb | 469 +++++++++++++----------- 3 files changed, 284 insertions(+), 214 deletions(-) diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index 0dc622cafd7..a49eb0076a7 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -146,6 +146,7 @@ def locked? def compare(revision) changes = [] changes += compare_revision_types_de_champ(revision_types_de_champ, revision.revision_types_de_champ) + changes += compare_transitions_rules(transitions_rules, revision.transitions_rules) changes end @@ -325,6 +326,19 @@ def compare_revision_types_de_champ(from_coordinates, to_coordinates) end end + def compare_transitions_rules(from_transitions_rules, to_transitions_rules) + from_h = from_transitions_rules + to_h = to_transitions_rules + + if from_h.present? && !to_h.present? + [ProcedureRevisionChange::RemoveTransitionsRule.new(from_h)] + elsif !from_h.present? && to_h.present? + [ProcedureRevisionChange::AddTransitionsRule.new(to_h)] + else + [ProcedureRevisionChange::ChangeTransitionsRule.new(from_h, to_h)] + end + end + def compare_type_de_champ(from_type_de_champ, to_type_de_champ, from_coordinates, to_coordinates) changes = [] if from_type_de_champ.type_champ != to_type_de_champ.type_champ diff --git a/app/models/procedure_revision_change.rb b/app/models/procedure_revision_change.rb index fc412cc261f..3e9e475d68d 100644 --- a/app/models/procedure_revision_change.rb +++ b/app/models/procedure_revision_change.rb @@ -75,4 +75,19 @@ def can_rebase?(dossier = nil) end end end + + class AddTransitionsRule < ProcedureRevisionChange + def op = :add + end + + class RemoveTransitionsRule < ProcedureRevisionChange + def op = :remove + end + + class ChangeTransitionsRule < ProcedureRevisionChange + def initialize(from, to) + end + + def op = :update + end end diff --git a/spec/models/procedure_revision_spec.rb b/spec/models/procedure_revision_spec.rb index 9d3ea5924d3..4db15393718 100644 --- a/spec/models/procedure_revision_spec.rb +++ b/spec/models/procedure_revision_spec.rb @@ -349,304 +349,345 @@ describe '#compare' do include Logic - - let(:first_tdc) { draft.types_de_champ_public.first } - let(:second_tdc) { draft.types_de_champ_public.second } let(:new_draft) { procedure.create_new_revision } - subject { procedure.active_revision.compare(new_draft.reload).map(&:to_h) } + describe 'when tdcs changes' do + subject { procedure.active_revision.compare(new_draft.reload).map(&:to_h) } - context 'with a procedure with 2 tdcs' do - let(:procedure) do - create(:procedure, types_de_champ_public: [ - { type: :integer_number, libelle: 'l1' }, - { type: :text, libelle: 'l2' } - ]) + let(:first_tdc) { draft.types_de_champ_public.first } + let(:second_tdc) { draft.types_de_champ_public.second } + + context 'with a procedure with 2 tdcs' do + let(:procedure) do + create(:procedure, types_de_champ_public: [ + { type: :integer_number, libelle: 'l1' }, + { type: :text, libelle: 'l2' } + ]) + end + + context 'when a condition is added' do + before do + second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) + second.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(3))) + end + + it do + is_expected.to eq([ + { + attribute: :condition, + from: nil, + label: "l2", + op: :update, + private: false, + stable_id: second_tdc.stable_id, + to: "(l1 == 3)" + } + ]) + end + end + + context 'when a condition is removed' do + before do + second_tdc.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(2))) + draft.reload + + second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) + second.update(condition: nil) + end + + it do + is_expected.to eq([ + { + attribute: :condition, + from: "(l1 == 2)", + label: "l2", + op: :update, + private: false, + stable_id: second_tdc.stable_id, + to: nil + } + ]) + end + end + + context 'when a condition is changed' do + before do + second_tdc.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(2))) + draft.reload + + second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) + second.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(3))) + end + + it do + is_expected.to eq([ + { + attribute: :condition, + from: "(l1 == 2)", + label: "l2", + op: :update, + private: false, + stable_id: second_tdc.stable_id, + to: "(l1 == 3)" + } + ]) + end + end end - context 'when a condition is added' do - before do - second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) - second.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(3))) + context 'when a type de champ is added' do + let(:procedure) { create(:procedure) } + let(:new_tdc) do + new_draft.add_type_de_champ( + type_champ: TypeDeChamp.type_champs.fetch(:text), + libelle: "Un champ text" + ) end + before { new_tdc } + it do is_expected.to eq([ { - attribute: :condition, - from: nil, - label: "l2", - op: :update, + op: :add, + label: "Un champ text", private: false, - stable_id: second_tdc.stable_id, - to: "(l1 == 3)" + mandatory: false, + stable_id: new_tdc.stable_id } ]) end end - context 'when a condition is removed' do - before do - second_tdc.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(2))) - draft.reload + context 'when a type de champ is changed' do + context 'when libelle, description, and mandatory are changed' do + let(:procedure) { create(:procedure, :with_type_de_champ) } - second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) - second.update(condition: nil) + before do + updated_tdc = new_draft.find_and_ensure_exclusive_use(first_tdc.stable_id) + + updated_tdc.update(libelle: 'modifier le libelle', description: 'une description', mandatory: !updated_tdc.mandatory) + end + + it do + is_expected.to eq([ + { + op: :update, + attribute: :libelle, + label: first_tdc.libelle, + private: false, + from: first_tdc.libelle, + to: "modifier le libelle", + stable_id: first_tdc.stable_id + }, + { + op: :update, + attribute: :description, + label: first_tdc.libelle, + private: false, + from: first_tdc.description, + to: "une description", + stable_id: first_tdc.stable_id + }, + { + op: :update, + attribute: :mandatory, + label: first_tdc.libelle, + private: false, + from: false, + to: true, + stable_id: first_tdc.stable_id + } + ]) + end + end + + context 'when collapsible_explanation_enabled and collapsible_explanation_text are changed' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :explication }]) } + + before do + updated_tdc = new_draft.find_and_ensure_exclusive_use(first_tdc.stable_id) + + updated_tdc.update(collapsible_explanation_enabled: "1", collapsible_explanation_text: 'afficher au clique') + end + it do + is_expected.to eq([ + { + op: :update, + attribute: :collapsible_explanation_enabled, + label: first_tdc.libelle, + private: first_tdc.private?, + from: false, + to: true, + stable_id: first_tdc.stable_id + }, + { + op: :update, + attribute: :collapsible_explanation_text, + label: first_tdc.libelle, + private: first_tdc.private?, + from: nil, + to: 'afficher au clique', + stable_id: first_tdc.stable_id + } + ]) + end + end + end + + context 'when a type de champ is moved' do + let(:procedure) { create(:procedure, types_de_champ_public: Array.new(3) { { type: :text } }) } + let(:new_draft_second_tdc) { new_draft.types_de_champ_public.second } + let(:new_draft_third_tdc) { new_draft.types_de_champ_public.third } + + before do + new_draft_second_tdc + new_draft_third_tdc + new_draft.move_type_de_champ(new_draft_second_tdc.stable_id, 2) end it do is_expected.to eq([ { - attribute: :condition, - from: "(l1 == 2)", - label: "l2", - op: :update, + op: :move, + label: new_draft_third_tdc.libelle, + private: false, + from: 2, + to: 1, + stable_id: new_draft_third_tdc.stable_id + }, + { + op: :move, + label: new_draft_second_tdc.libelle, private: false, - stable_id: second_tdc.stable_id, - to: nil + from: 1, + to: 2, + stable_id: new_draft_second_tdc.stable_id } ]) end end - context 'when a condition is changed' do - before do - second_tdc.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(2))) - draft.reload + context 'when a type de champ is removed' do + let(:procedure) { create(:procedure, :with_type_de_champ) } - second = new_draft.find_and_ensure_exclusive_use(second_tdc.stable_id) - second.update(condition: ds_eq(champ_value(first_tdc.stable_id), constant(3))) + before do + new_draft.remove_type_de_champ(first_tdc.stable_id) end it do is_expected.to eq([ { - attribute: :condition, - from: "(l1 == 2)", - label: "l2", - op: :update, + op: :remove, + label: first_tdc.libelle, private: false, - stable_id: second_tdc.stable_id, - to: "(l1 == 3)" + stable_id: first_tdc.stable_id } ]) end end - end - - context 'when a type de champ is added' do - let(:procedure) { create(:procedure) } - let(:new_tdc) do - new_draft.add_type_de_champ( - type_champ: TypeDeChamp.type_champs.fetch(:text), - libelle: "Un champ text" - ) - end - - before { new_tdc } - - it do - is_expected.to eq([ - { - op: :add, - label: "Un champ text", - private: false, - mandatory: false, - stable_id: new_tdc.stable_id - } - ]) - end - end - context 'when a type de champ is changed' do - context 'when libelle, description, and mandatory are changed' do - let(:procedure) { create(:procedure, :with_type_de_champ) } + context 'when a child type de champ is transformed into a drop_down_list' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text, libelle: 'sub type de champ' }, { type: :integer_number }] }]) } before do - updated_tdc = new_draft.find_and_ensure_exclusive_use(first_tdc.stable_id) - - updated_tdc.update(libelle: 'modifier le libelle', description: 'une description', mandatory: !updated_tdc.mandatory) + child = new_draft.children_of(new_draft.types_de_champ_public.last).first + new_draft.find_and_ensure_exclusive_use(child.stable_id).update(type_champ: :drop_down_list, drop_down_options: ['one', 'two']) end it do is_expected.to eq([ { op: :update, - attribute: :libelle, - label: first_tdc.libelle, + attribute: :type_champ, + label: "sub type de champ", private: false, - from: first_tdc.libelle, - to: "modifier le libelle", - stable_id: first_tdc.stable_id - }, - { - op: :update, - attribute: :description, - label: first_tdc.libelle, - private: false, - from: first_tdc.description, - to: "une description", - stable_id: first_tdc.stable_id + from: "text", + to: "drop_down_list", + stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id }, { op: :update, - attribute: :mandatory, - label: first_tdc.libelle, + attribute: :drop_down_options, + label: "sub type de champ", private: false, - from: false, - to: true, - stable_id: first_tdc.stable_id + from: [], + to: ["one", "two"], + stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id } ]) end end - context 'when collapsible_explanation_enabled and collapsible_explanation_text are changed' do - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :explication }]) } + context 'when a child type de champ is transformed into a map' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text, libelle: 'sub type de champ' }, { type: :integer_number }] }]) } before do - updated_tdc = new_draft.find_and_ensure_exclusive_use(first_tdc.stable_id) - - updated_tdc.update(collapsible_explanation_enabled: "1", collapsible_explanation_text: 'afficher au clique') + child = new_draft.children_of(new_draft.types_de_champ_public.last).first + new_draft.find_and_ensure_exclusive_use(child.stable_id).update(type_champ: :carte, options: { cadastres: true, znieff: true }) end + it do is_expected.to eq([ { op: :update, - attribute: :collapsible_explanation_enabled, - label: first_tdc.libelle, - private: first_tdc.private?, - from: false, - to: true, - stable_id: first_tdc.stable_id + attribute: :type_champ, + label: "sub type de champ", + private: false, + from: "text", + to: "carte", + stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id }, { op: :update, - attribute: :collapsible_explanation_text, - label: first_tdc.libelle, - private: first_tdc.private?, - from: nil, - to: 'afficher au clique', - stable_id: first_tdc.stable_id + attribute: :carte_layers, + label: "sub type de champ", + private: false, + from: [], + to: [:cadastres, :znieff], + stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id } ]) end end end - context 'when a type de champ is moved' do - let(:procedure) { create(:procedure, types_de_champ_public: Array.new(3) { { type: :text } }) } - let(:new_draft_second_tdc) { new_draft.types_de_champ_public.second } - let(:new_draft_third_tdc) { new_draft.types_de_champ_public.third } + context 'when transitions_rules changes' do + subject { procedure.active_revision.compare(new_draft.reload) } - before do - new_draft_second_tdc - new_draft_third_tdc - new_draft.move_type_de_champ(new_draft_second_tdc.stable_id, 2) - end - - it do - is_expected.to eq([ - { - op: :move, - label: new_draft_third_tdc.libelle, - private: false, - from: 2, - to: 1, - stable_id: new_draft_third_tdc.stable_id - }, - { - op: :move, - label: new_draft_second_tdc.libelle, - private: false, - from: 1, - to: 2, - stable_id: new_draft_second_tdc.stable_id - } - ]) + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :yes_no }] } + let(:yes_no_tdc) { new_draft.types_de_champ_public.first } + context 'when nothing changed' do + it { is_expected.to be_empty } end - end - context 'when a type de champ is removed' do - let(:procedure) { create(:procedure, :with_type_de_champ) } + context 'when transitions_rules added' do + before do + new_draft.update!(transitions_rules: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true))) + end - before do - new_draft.remove_type_de_champ(first_tdc.stable_id) + it { is_expected.to include(an_instance_of(ProcedureRevisionChange::AddTransitionsRule)) } end - it do - is_expected.to eq([ - { - op: :remove, - label: first_tdc.libelle, - private: false, - stable_id: first_tdc.stable_id - } - ]) - end - end - - context 'when a child type de champ is transformed into a drop_down_list' do - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text, libelle: 'sub type de champ' }, { type: :integer_number }] }]) } + context 'when transitions_rules removed' do + before do + procedure.published_revision.update!(transitions_rules: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true))) + end - before do - child = new_draft.children_of(new_draft.types_de_champ_public.last).first - new_draft.find_and_ensure_exclusive_use(child.stable_id).update(type_champ: :drop_down_list, drop_down_options: ['one', 'two']) + it { is_expected.to include(an_instance_of(ProcedureRevisionChange::RemoveTransitionsRule)) } end - it do - is_expected.to eq([ - { - op: :update, - attribute: :type_champ, - label: "sub type de champ", - private: false, - from: "text", - to: "drop_down_list", - stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id - }, - { - op: :update, - attribute: :drop_down_options, - label: "sub type de champ", - private: false, - from: [], - to: ["one", "two"], - stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id - } - ]) - end - end - - context 'when a child type de champ is transformed into a map' do - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text, libelle: 'sub type de champ' }, { type: :integer_number }] }]) } - - before do - child = new_draft.children_of(new_draft.types_de_champ_public.last).first - new_draft.find_and_ensure_exclusive_use(child.stable_id).update(type_champ: :carte, options: { cadastres: true, znieff: true }) - end + context 'when transitions_rules changed' do + before do + procedure.published_revision.update!(transitions_rules: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true))) + new_draft.update!(transitions_rules: ds_and([ + ds_eq(champ_value(yes_no_tdc.stable_id), constant(true)), + empty_operator(empty, empty) + ])) + end - it do - is_expected.to eq([ - { - op: :update, - attribute: :type_champ, - label: "sub type de champ", - private: false, - from: "text", - to: "carte", - stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id - }, - { - op: :update, - attribute: :carte_layers, - label: "sub type de champ", - private: false, - from: [], - to: [:cadastres, :znieff], - stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id - } - ]) + it { is_expected.to include(an_instance_of(ProcedureRevisionChange::ChangeTransitionsRule)) } end end end