From f1bcb84832038ca66e0886317daa2847a38c09ac Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 24 Apr 2023 18:48:05 +0200 Subject: [PATCH] fix: replace ds_eq operator by ds_include when targeted_champ is a multiple_drop_down_list --- .../20230424154715_fix_include_in_logic.rake | 54 ++++++++ ...24154715_fix_include_in_logic.rake_spec.rb | 123 ++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 lib/tasks/deployment/20230424154715_fix_include_in_logic.rake create mode 100644 spec/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake_spec.rb diff --git a/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake b/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake new file mode 100644 index 000000000..72123e01a --- /dev/null +++ b/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake @@ -0,0 +1,54 @@ +namespace :after_party do + desc 'Deployment task: fix_include_in_logic' + task fix_include_in_logic: :environment do + include Logic + puts "Running deploy task 'fix_include_in_logic'" + + tdcs_with_condition = TypeDeChamp.where.not(condition: nil) + + progress = ProgressReport.new(tdcs_with_condition.count) + + tdcs_with_condition.find_each do |tdc| + begin + tdc.revisions.each do |revision| + tdcs = revision.types_de_champ.where(stable_id: tdc.condition.sources) + + transformed_condition = transform_eq_to_include(tdc.condition, tdcs) + + if (transformed_condition != tdc.condition) + rake_puts "found #{tdc.id}, original: #{tdc.condition.to_s(tdcs)}, correction: #{transformed_condition.to_s(tdcs)}!" + new_tdc = revision.find_and_ensure_exclusive_use(tdc.stable_id) + new_tdc.update_columns(condition: transformed_condition) + Champ.joins(:dossier).where(dossier: { revision: revision }, type_de_champ: tdc).update(type_de_champ: new_tdc) + end + end + rescue StandardError => e + rake_puts "problem with tdc #{tdc.id},\ncondition: #{tdc.read_attribute_before_type_cast('condition')},\nmessage: #{e.message}" + ensure + progress.inc + end + end + progress.finish + + # Update task as completed. If you remove the line below, the task will + # run with every deploy (or every time you call after_party:run). + AfterParty::TaskRecord + .create version: AfterParty::TaskRecorder.new(__FILE__).timestamp + end + + def transform_eq_to_include(condition, tdcs) + case condition + when Logic::NAryOperator + condition.class.new(condition.operands.map { transform_eq_to_include(_1, tdcs) }) + when Eq + target = tdcs.find { _1.stable_id == condition.left.stable_id } + if target.type_champ == 'multiple_drop_down_list' + ds_include(condition.left, condition.right) + else + condition + end + else + condition + end + end +end diff --git a/spec/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake_spec.rb b/spec/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake_spec.rb new file mode 100644 index 000000000..1d795c02c --- /dev/null +++ b/spec/lib/tasks/deployment/20230424154715_fix_include_in_logic.rake_spec.rb @@ -0,0 +1,123 @@ +describe '20230424154715_fix_include_in_logic.rake' do + let(:rake_task) { Rake::Task['after_party:fix_include_in_logic'] } + + include Logic + + subject(:run_task) { rake_task.invoke } + after { rake_task.reenable } + + context 'test condition correction' do + let(:procedure) do + types_de_champ_public = [ + { type: :multiple_drop_down_list }, + { type: :drop_down_list }, + { type: :integer_number }, + { type: :text } + ] + create(:procedure, :published, types_de_champ_public:) + end + + def multiple_stable_id = procedure.reload.published_types_de_champ_public.first.stable_id + def simple_stable_id = procedure.reload.published_types_de_champ_public.second.stable_id + def integer_tdc = procedure.reload.published_types_de_champ_public.third + def text_tdc = procedure.reload.published_types_de_champ_public.last + + before do + and_condition = ds_and([ + # incorrect: should change ds_eq => ds_include + ds_eq(champ_value(multiple_stable_id), constant("a")), + # correct + ds_include(champ_value(multiple_stable_id), constant("b")), + # correct ds_eq because drop_down_list + ds_eq(champ_value(simple_stable_id), constant("c")) + ]) + + text_tdc.update(condition: and_condition) + + or_condition = ds_or([ + # incorrect: should change ds_eq => ds_include + ds_eq(champ_value(multiple_stable_id), constant("a")) + ]) + + integer_tdc.update(condition: or_condition) + end + + it do + run_task + expected_and_condition = ds_and([ + ds_include(champ_value(multiple_stable_id), constant("a")), + ds_include(champ_value(multiple_stable_id), constant("b")), + ds_eq(champ_value(simple_stable_id), constant("c")) + ]) + + expect(text_tdc.condition).to eq(expected_and_condition) + + expected_or_condition = ds_or([ + ds_include(champ_value(multiple_stable_id), constant("a")) + ]) + + expect(integer_tdc.condition).to eq(expected_or_condition) + end + end + + context 'test revision scope' do + let(:procedure) do + types_de_champ_public = [ + { type: :drop_down_list, options: [:a, :b, :c] }, + { type: :text } + ] + create(:procedure, types_de_champ_public:) + end + + let(:initial_condition) { ds_eq(champ_value(drop_down_stable_id), constant('a')) } + + def drop_down_stable_id = procedure.reload.draft_types_de_champ_public.first.stable_id + def draft_text = procedure.reload.draft_types_de_champ_public.last + def published_text = procedure.reload.published_types_de_champ_public.last + + before do + draft_text.update(condition: initial_condition) + + procedure.publish! + procedure.reload + + draft_drop_down = procedure.draft_revision.find_and_ensure_exclusive_use(drop_down_stable_id) + draft_drop_down.update(type_champ: 'multiple_drop_down_list') + end + + it do + expect(draft_text.condition).to eq(initial_condition) + expect(published_text.condition).to eq(initial_condition) + + run_task + + # the text condition is invalid for the draft revision + expect(draft_text.condition).to eq(ds_include(champ_value(drop_down_stable_id), constant('a'))) + # the published_text condition is untouched as it s still valid + expect(published_text.condition).to eq(initial_condition) + end + end + + context 'test champ change' do + let!(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :multiple_drop_down_list, options: ['a'] }, { type: :text }]) } + let!(:dossier) { create(:dossier, procedure:) } + + def multiple_stable_id = procedure.reload.published_types_de_champ_public.first.stable_id + def text_tdc = procedure.reload.published_types_de_champ_public.last + + let(:initial_condition) { ds_eq(champ_value(multiple_stable_id), constant('a')) } + let(:fixed_condition) { ds_include(champ_value(multiple_stable_id), constant('a')) } + + before do + text_tdc.update(condition: initial_condition) + end + + it do + expect(dossier.reload.champs_public.last.type_de_champ.condition).to eq(initial_condition) + + run_task + + expect(dossier.reload.champs_public.last.type_de_champ.condition).to eq(fixed_condition) + end + end +end