diff --git a/app/models/champ.rb b/app/models/champ.rb index 9daa99d41..e193a7a10 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -4,19 +4,17 @@ class Champ < ApplicationRecord include ChampConditionalConcern include ChampsValidateConcern - self.ignored_columns += [:type_de_champ_id] + self.ignored_columns += [:type_de_champ_id, :parent_id] attr_readonly :stable_id belongs_to :dossier, inverse_of: false, touch: true, optional: false - belongs_to :parent, class_name: 'Champ', optional: true has_many_attached :piece_justificative_file # We declare champ specific relationships (Champs::CarteChamp, Champs::SiretChamp and Champs::RepetitionChamp) # here because otherwise we can't easily use includes in our queries. has_many :geo_areas, -> { order(:created_at) }, dependent: :destroy, inverse_of: :champ belongs_to :etablissement, optional: true, dependent: :destroy - has_many :champs, foreign_key: :parent_id, inverse_of: :parent delegate :procedure, to: :dossier @@ -79,13 +77,8 @@ class Champ < ApplicationRecord delegate :used_by_routing_rules?, to: :type_de_champ scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) } - scope :public_only, -> { where(private: false) } - scope :private_only, -> { where(private: true) } - scope :root, -> { where(parent_id: nil) } scope :prefilled, -> { where(prefilled: true) } - before_create :set_dossier_id, if: :needs_dossier_id? - before_validation :set_dossier_id, if: :needs_dossier_id? before_save :cleanup_if_empty before_save :normalize after_update_commit :fetch_external_data_later @@ -232,7 +225,7 @@ class Champ < ApplicationRecord end def clone(fork = false) - champ_attributes = [:parent_id, :private, :row_id, :type, :stable_id, :stream] + champ_attributes = [:private, :row_id, :type, :stable_id, :stream] value_attributes = fork || !private? ? [:value, :value_json, :data, :external_id] : [] relationships = fork || !private? ? [:etablissement, :geo_areas] : [] @@ -265,14 +258,6 @@ class Champ < ApplicationRecord type_de_champ.html_id(row_id) end - def needs_dossier_id? - !dossier_id && parent_id - end - - def set_dossier_id - self.dossier_id = parent.dossier_id - end - def cleanup_if_empty if fetch_external_data? && persisted? && external_id_changed? self.data = nil diff --git a/app/models/champs/repetition_champ.rb b/app/models/champs/repetition_champ.rb index e289171dc..cfa6ff5ab 100644 --- a/app/models/champs/repetition_champ.rb +++ b/app/models/champs/repetition_champ.rb @@ -12,11 +12,7 @@ class Champs::RepetitionChamp < Champ end def add_row(updated_by:) - # TODO: clean this up when parent_id is deprecated - row_id, added_champs = dossier.repetition_add_row(type_de_champ, updated_by:) - self.champs << added_champs - dossier.champs.reload if dossier.persisted? - row_id + dossier.repetition_add_row(type_de_champ, updated_by:) end def remove_row(row_id, updated_by:) diff --git a/app/models/concerns/dossier_champs_concern.rb b/app/models/concerns/dossier_champs_concern.rb index f6e3f4b96..657b93325 100644 --- a/app/models/concerns/dossier_champs_concern.rb +++ b/app/models/concerns/dossier_champs_concern.rb @@ -40,7 +40,7 @@ module DossierChampsConcern end def project_rows_for(type_de_champ) - [] if !type_de_champ.repetition? + return [] if !type_de_champ.repetition? children = revision.children_of(type_de_champ) row_ids = repetition_row_ids(type_de_champ) @@ -84,7 +84,7 @@ module DossierChampsConcern end def repetition_row_ids(type_de_champ) - [] if !type_de_champ.repetition? + return [] if !type_de_champ.repetition? stable_ids = revision.children_of(type_de_champ).map(&:stable_id) champs.filter { _1.stable_id.in?(stable_ids) && _1.row_id.present? } @@ -98,10 +98,10 @@ module DossierChampsConcern row_id = ULID.generate types_de_champ = revision.children_of(type_de_champ) - # TODO: clean this up when parent_id is deprecated - added_champs = types_de_champ.map { _1.build_champ(row_id:, updated_by:) } + self.champs += types_de_champ.map { _1.build_champ(row_id:, updated_by:) } + champs.reload if persisted? @champs_by_public_id = nil - [row_id, added_champs] + row_id end def repetition_remove_row(type_de_champ, row_id, updated_by:) @@ -158,13 +158,6 @@ module DossierChampsConcern attributes[:data] = nil end - parent = revision.parent_of(type_de_champ) - if parent.present? - attributes[:parent] = champs.find { _1.stable_id == parent.stable_id } - else - attributes[:parent] = nil - end - @champs_by_public_id = nil [champ, attributes] diff --git a/app/models/concerns/dossier_clone_concern.rb b/app/models/concerns/dossier_clone_concern.rb index 6d7b185e4..07750548c 100644 --- a/app/models/concerns/dossier_clone_concern.rb +++ b/app/models/concerns/dossier_clone_concern.rb @@ -101,7 +101,6 @@ module DossierCloneConcern kopy.state = Dossier.states.fetch(:brouillon) kopy.champs = cloned_champs.values.map do |(_, champ)| champ.dossier = kopy - champ.parent = cloned_champs[champ.parent_id].second if champ.child? champ end end @@ -152,33 +151,16 @@ module DossierCloneConcern def apply_diff(diff) champs_index = (champs_for_revision(scope: :public) + diff[:added]).index_by(&:public_id) - diff[:added].each do |champ| - if champ.child? - champ.update_columns(dossier_id: id, parent_id: champs_index.fetch(champ.parent.public_id).id) - else - champ.update_column(:dossier_id, id) - end - end + diff[:added].each { _1.update_column(:dossier_id, id) } - champs_to_remove = [] + # a bit of a hack to work around unicity index + remove_group_id = ULID.generate diff[:updated].each do |champ| - old_champ = champs_index.fetch(champ.public_id) - champs_to_remove << old_champ - - if champ.child? - # we need to do that in order to avoid a foreign key constraint - old_champ.update(row_id: nil) - champ.update_columns(dossier_id: id, parent_id: champs_index.fetch(champ.parent.public_id).id) - else - champ.update_column(:dossier_id, id) - end + champs_index.fetch(champ.public_id).update(row_id: remove_group_id) + champ.update_column(:dossier_id, id) end - champs_to_remove += diff[:removed] - children_champs_to_remove, root_champs_to_remove = champs_to_remove.partition(&:child?) - - children_champs_to_remove.each(&:destroy!) - Champ.where(parent_id: root_champs_to_remove.map(&:id)).destroy_all - root_champs_to_remove.each(&:destroy!) + Champ.where(row_id: remove_group_id).destroy_all + diff[:removed].each(&:destroy!) end end diff --git a/app/models/concerns/dossier_rebase_concern.rb b/app/models/concerns/dossier_rebase_concern.rb index 7ee91914d..b0932166b 100644 --- a/app/models/concerns/dossier_rebase_concern.rb +++ b/app/models/concerns/dossier_rebase_concern.rb @@ -65,9 +65,7 @@ module DossierRebaseConcern .tap { _1.default = Champ.none } # remove champ - children_champ, root_champ = changes_by_op[:remove].partition(&:child?) - children_champ.each { champs_by_stable_id[_1.stable_id].destroy_all } - root_champ.each { champs_by_stable_id[_1.stable_id].destroy_all } + changes_by_op[:remove].each { champs_by_stable_id[_1.stable_id].destroy_all } # update champ changes_by_op[:update].each { apply(_1, champs_by_stable_id[_1.stable_id]) } @@ -78,8 +76,6 @@ module DossierRebaseConcern # add champ (after changing dossier revision to avoid errors) changes_by_op[:add] .map { target_coordinates_by_stable_id[_1.stable_id] } - # add parent champs first so we can then add children - .sort_by { _1.child? ? 1 : 0 } .each { add_new_champs_for_revision(_1) } end @@ -119,28 +115,24 @@ module DossierRebaseConcern def add_new_champs_for_revision(target_coordinate) if target_coordinate.child? - # If this type de champ is a child, we create a new champ for each row of the parent - parent_stable_id = target_coordinate.parent.stable_id + row_ids = repetition_row_ids(target_coordinate.parent.type_de_champ) - champs.filter { _1.stable_id == parent_stable_id }.each do |champ_repetition| - if champ_repetition.champs.present? - champ_repetition.champs.map(&:row_id).uniq.each do |row_id| - champs << create_champ(target_coordinate, champ_repetition, row_id:) - end - elsif target_coordinate.parent.mandatory? - champs << create_champ(target_coordinate, champ_repetition, row_id: ULID.generate) + if row_ids.present? + row_ids.each do |row_id| + create_champ(target_coordinate, row_id:) end + elsif target_coordinate.parent.mandatory? + create_champ(target_coordinate, row_id: ULID.generate) end else - create_champ(target_coordinate, self) + create_champ(target_coordinate) end end - def create_champ(target_coordinate, parent, row_id: nil) - target_coordinate + def create_champ(target_coordinate, row_id: nil) + self.champs << target_coordinate .type_de_champ .build_champ(rebased_at: Time.zone.now, row_id:) - .tap { parent.champs << _1 } end def purge_piece_justificative_file(champ) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 03658337a..b2d495d01 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -45,11 +45,7 @@ class Dossier < ApplicationRecord has_one_attached :justificatif_motivation - has_many :champs - # We have to remove champs in a particular order - champs with a reference to a parent have to be - # removed first, otherwise we get a foreign key constraint error. - has_many :champs_to_destroy, -> { order(:parent_id) }, class_name: 'Champ', inverse_of: false, dependent: :destroy - + has_many :champs, dependent: :destroy has_many :commentaires, inverse_of: :dossier, dependent: :destroy has_many :preloaded_commentaires, -> { includes(:dossier_correction, piece_jointe_attachments: :blob) }, class_name: 'Commentaire', inverse_of: :dossier @@ -1160,12 +1156,12 @@ class Dossier < ApplicationRecord def build_default_champs_for(types_de_champ) self.champs << types_de_champ.flat_map do |type_de_champ| + champ = type_de_champ.build_champ(dossier: self) if type_de_champ.repetition? && (type_de_champ.private? || type_de_champ.mandatory?) row_id = ULID.generate - parent = type_de_champ.build_champ(dossier: self) - [parent] + revision.children_of(type_de_champ).map { _1.build_champ(dossier: self, parent:, row_id:) } + [champ] + revision.children_of(type_de_champ).map { _1.build_champ(dossier: self, row_id:) } else - type_de_champ.build_champ(dossier: self) + champ end end end diff --git a/app/models/dossier_preloader.rb b/app/models/dossier_preloader.rb index 9b27f47cc..c1f8d82fa 100644 --- a/app/models/dossier_preloader.rb +++ b/app/models/dossier_preloader.rb @@ -81,20 +81,8 @@ class DossierPreloader end dossier.association(:champs).target = champs - # remove once parent_id is deprecated - champs_by_parent_id = champs.group_by(&:parent_id) - champs.each do |champ| champ.association(:dossier).target = dossier - - # remove once parent_id is deprecated - if champ.repetition? - children = champs_by_parent_id.fetch(champ.id, []) - children.each do |child| - child.association(:parent).target = champ - end - champ.association(:champs).target = children - end end # We need to do this because of the check on `Etablissement#champ` in diff --git a/app/tasks/maintenance/rescue_dossier_with_invalid_repetition_task.rb b/app/tasks/maintenance/rescue_dossier_with_invalid_repetition_task.rb deleted file mode 100644 index c65ac899a..000000000 --- a/app/tasks/maintenance/rescue_dossier_with_invalid_repetition_task.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -module Maintenance - class RescueDossierWithInvalidRepetitionTask < MaintenanceTasks::Task - INVALID_RELEASE_DATETIME = DateTime.new(2024, 8, 30, 12) - def collection - Dossier.where("last_champ_updated_at > ?", INVALID_RELEASE_DATETIME).pluck(:id) # heure de l'incident - end - - def process(dossier_id) - Dossier.find(dossier_id) - .champs - .filter { _1.row_id.present? && _1.parent_id.blank? } - .each(&:destroy!) - rescue ActiveRecord::RecordNotFound - # some dossier had already been destroyed - end - - def count - # Optionally, define the number of rows that will be iterated over - # This is used to track the task's progress - end - end -end diff --git a/db/migrate/20240321081721_remove_champs_foreign_key.rb b/db/migrate/20240321081721_remove_champs_foreign_key.rb new file mode 100644 index 000000000..8d4060ba2 --- /dev/null +++ b/db/migrate/20240321081721_remove_champs_foreign_key.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class RemoveChampsForeignKey < ActiveRecord::Migration[7.0] + def change + remove_foreign_key :champs, column: :parent_id + remove_index :champs, :parent_id + end +end diff --git a/db/schema.rb b/db/schema.rb index f8f7dca89..76e7f27c5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -270,7 +270,6 @@ ActiveRecord::Schema[7.0].define(version: 2024_09_29_141825) do t.index ["dossier_id", "stream", "stable_id", "row_id"], name: "index_champs_on_dossier_id_and_stream_and_stable_id_and_row_id", unique: true t.index ["dossier_id"], name: "index_champs_on_dossier_id" t.index ["etablissement_id"], name: "index_champs_on_etablissement_id" - t.index ["parent_id"], name: "index_champs_on_parent_id" t.index ["row_id"], name: "index_champs_on_row_id" t.index ["stable_id"], name: "index_champs_on_stable_id" t.index ["type"], name: "index_champs_on_type" @@ -1264,7 +1263,6 @@ ActiveRecord::Schema[7.0].define(version: 2024_09_29_141825) do add_foreign_key "avis", "experts_procedures" add_foreign_key "batch_operations", "instructeurs" add_foreign_key "bulk_messages", "procedures" - add_foreign_key "champs", "champs", column: "parent_id" add_foreign_key "champs", "dossiers" add_foreign_key "champs", "etablissements" add_foreign_key "champs", "types_de_champ" diff --git a/spec/components/editable_champ/editable_champ_component_spec.rb b/spec/components/editable_champ/editable_champ_component_spec.rb index 190a8e162..d9669580e 100644 --- a/spec/components/editable_champ/editable_champ_component_spec.rb +++ b/spec/components/editable_champ/editable_champ_component_spec.rb @@ -5,7 +5,7 @@ describe EditableChamp::EditableChampComponent, type: :component do let(:types_de_champ_public) { [] } let(:types_de_champ_private) { [] } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } - let(:champ) { dossier.champs.first } + let(:champ) { (dossier.project_champs_public + dossier.project_champs_private).first } let(:component) { described_class.new(form: nil, champ:) } diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index 42a4a3bd3..4ad9070b2 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -1037,7 +1037,7 @@ describe Instructeurs::DossiersController, type: :controller do primary_value: 'primary', secondary_value: 'secondary' }, - champ_repetition.champs.first.public_id => { + champ_repetition.rows.first.first.public_id => { value: 'text' }, champ_drop_down_list.public_id => { @@ -1054,7 +1054,7 @@ describe Instructeurs::DossiersController, type: :controller do expect(champ_linked_drop_down_list.primary_value).to eq('primary') expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') expect(champ_datetime.value).to eq(Time.zone.parse('2019-12-21T13:17:00').iso8601) - expect(champ_repetition.champs.first.value).to eq('text') + expect(champ_repetition.rows.first.first.value).to eq('text') expect(champ_drop_down_list.value).to eq('other value') expect(dossier.reload.last_champ_private_updated_at).to eq(now) expect(response).to have_http_status(200) diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index eea830d0f..e3f173c0a 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -196,8 +196,8 @@ FactoryBot.define do evaluator.rows.times do row_id = ULID.generate - champ_repetition.champs << types_de_champ.map do |type_de_champ| - attrs = { dossier: champ_repetition.dossier, parent: champ_repetition, private: champ_repetition.private?, stable_id: type_de_champ.stable_id, row_id: } + champ_repetition.dossier.champs << types_de_champ.map do |type_de_champ| + attrs = { dossier: champ_repetition.dossier, private: champ_repetition.private?, stable_id: type_de_champ.stable_id, row_id: } build(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) end end diff --git a/spec/graphql/annotation_spec.rb b/spec/graphql/annotation_spec.rb index cd3d731f1..480b0a96b 100644 --- a/spec/graphql/annotation_spec.rb +++ b/spec/graphql/annotation_spec.rb @@ -48,14 +48,14 @@ RSpec.describe Mutations::DossierModifierAnnotation, type: :graphql do end it 'add row' do - expect(annotation.champs.size).to eq(4) + expect(annotation.row_ids.size).to eq(2) expect(data).to eq(dossierModifierAnnotationAjouterLigne: { annotation: { id: annotation.to_typed_id }, errors: nil }) - expect(annotation.reload.champs.size).to eq(6) + expect(annotation.reload.row_ids.size).to eq(3) end end diff --git a/spec/lib/recovery/dossier_life_cycle_spec.rb b/spec/lib/recovery/dossier_life_cycle_spec.rb index 863e3e8fe..3a6a05d4b 100644 --- a/spec/lib/recovery/dossier_life_cycle_spec.rb +++ b/spec/lib/recovery/dossier_life_cycle_spec.rb @@ -83,7 +83,7 @@ describe 'Dossier::Recovery::LifeCycle' do expect(reloaded_dossier.champs.count).not_to be(0) - expect(repetition(reloaded_dossier).champs.map(&:type)).to match_array(["Champs::PieceJustificativeChamp"]) + expect(repetition(reloaded_dossier).rows.flatten.map(&:type)).to match_array(["Champs::PieceJustificativeChamp"]) expect(pj_champ(reloaded_dossier).piece_justificative_file).to be_attached expect(carte(reloaded_dossier).geo_areas).to be_present diff --git a/spec/models/champ_presentations/repetition_presentation_spec.rb b/spec/models/champ_presentations/repetition_presentation_spec.rb index 3c1e1696e..66c498dd7 100644 --- a/spec/models/champ_presentations/repetition_presentation_spec.rb +++ b/spec/models/champ_presentations/repetition_presentation_spec.rb @@ -34,7 +34,7 @@ describe ChampPresentations::RepetitionPresentation do stars.update(value: 4) end - let(:representation) { described_class.new(libelle, dossier.champs[0].reload.rows) } + let(:representation) { described_class.new(libelle, champ_repetition.rows) } describe '#to_s' do it 'returns a key-value representation' do diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index 016c7f2e0..5c473b1fe 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -75,44 +75,27 @@ describe Champ do end end - describe '#public?' do + describe 'public and private' do let(:champ) { Champ.new } - - it { expect(champ.public?).to be_truthy } - it { expect(champ.private?).to be_falsey } - end - - describe '#public_only' do let(:dossier) { create(:dossier) } it 'partition public and private' do expect(dossier.project_champs_public.count).to eq(1) expect(dossier.project_champs_private.count).to eq(1) end - end - describe '#public_ordered' do - let(:procedure) { create(:simple_procedure) } - let(:dossier) { create(:dossier, procedure: procedure) } + it { expect(champ.public?).to be_truthy } + it { expect(champ.private?).to be_falsey } context 'when a procedure has 2 revisions' do - it 'does not duplicate the champs' do + it { expect(dossier.procedure.revisions.count).to eq(2) } + + it 'does not duplicate public champs' do expect(dossier.project_champs_public.count).to eq(1) - expect(procedure.revisions.count).to eq(2) end - end - end - describe '#private_ordered' do - let(:procedure) { create(:procedure, :with_type_de_champ_private) } - let(:dossier) { create(:dossier, procedure: procedure) } - - context 'when a procedure has 2 revisions' do - before { procedure.publish } - - it 'does not duplicate the champs private' do + it 'does not duplicate private champs' do expect(dossier.project_champs_private.count).to eq(1) - expect(procedure.revisions.count).to eq(2) end end end @@ -598,16 +581,6 @@ describe Champ do let(:champ) { Champs::TextChamp.new(private: true) } it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } end - - context "when has parent" do - let(:champ) { Champs::TextChamp.new(parent: Champs::TextChamp.new) } - it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" } - end - - context "when has private parent" do - let(:champ) { Champs::TextChamp.new(private: true, parent: Champs::TextChamp.new(private: true)) } - it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } - end end describe 'dom_id' do diff --git a/spec/models/champs/repetition_champ_spec.rb b/spec/models/champs/repetition_champ_spec.rb index d63dec474..16a537b73 100644 --- a/spec/models/champs/repetition_champ_spec.rb +++ b/spec/models/champs/repetition_champ_spec.rb @@ -11,7 +11,7 @@ describe Champs::RepetitionChamp do ]) } let(:dossier) { create(:dossier, procedure:) } - let(:champ) { dossier.champs.first } + let(:champ) { dossier.champs.find(&:repetition?) } describe "#for_tag" do before do diff --git a/spec/models/concerns/dossier_champs_concern_spec.rb b/spec/models/concerns/dossier_champs_concern_spec.rb index 08106be52..79689ff44 100644 --- a/spec/models/concerns/dossier_champs_concern_spec.rb +++ b/spec/models/concerns/dossier_champs_concern_spec.rb @@ -49,7 +49,6 @@ RSpec.describe DossierChampsConcern do it { expect(subject.persisted?).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } context "invalid row_id" do @@ -137,12 +136,7 @@ RSpec.describe DossierChampsConcern do describe '#repetition_add_row' do let(:type_de_champ_repetition) { dossier.find_type_de_champ_by_stable_id(993) } let(:row_ids) { dossier.repetition_row_ids(type_de_champ_repetition) } - subject do - # TODO: clean this up when parent_id is deprecated - row_id, added_champs = dossier.repetition_add_row(type_de_champ_repetition, updated_by: 'test') - dossier.champs << added_champs - row_id - end + subject { dossier.repetition_add_row(type_de_champ_repetition, updated_by: 'test') } it { expect { subject }.to change { dossier.repetition_row_ids(type_de_champ_repetition).size }.by(1) } it { expect(subject).to be_in(row_ids) } @@ -206,7 +200,6 @@ RSpec.describe DossierChampsConcern do it { expect(subject.persisted?).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } end @@ -226,7 +219,6 @@ RSpec.describe DossierChampsConcern do expect(subject.persisted?).to be_truthy expect(subject.is_a?(Champs::TextChamp)).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } end end diff --git a/spec/models/concerns/dossier_clone_concern_spec.rb b/spec/models/concerns/dossier_clone_concern_spec.rb index dd33470ab..9629d5df5 100644 --- a/spec/models/concerns/dossier_clone_concern_spec.rb +++ b/spec/models/concerns/dossier_clone_concern_spec.rb @@ -135,12 +135,13 @@ RSpec.describe DossierCloneConcern do context 'for Champs::Repetition with rows, original_champ.repetition and rows are duped' do let(:types_de_champ_public) { [{ type: :repetition, children: [{}, {}] }] } - let(:champ_repetition) { dossier.champs.first } - let(:cloned_champ_repetition) { new_dossier.champs.first } + let(:champ_repetition) { dossier.champs.find(&:repetition?) } + let(:cloned_champ_repetition) { new_dossier.champs.find(&:repetition?) } it do - expect(cloned_champ_repetition.champs.count).to eq(4) - expect(cloned_champ_repetition.champs.ids).not_to eq(champ_repetition.champs.ids) + expect(cloned_champ_repetition.rows.flatten.count).to eq(4) + expect(cloned_champ_repetition.rows.flatten.map(&:id)).not_to eq(champ_repetition.rows.flatten.map(&:id)) + expect(cloned_champ_repetition.row_ids).to eq(champ_repetition.row_ids) end end @@ -407,9 +408,7 @@ RSpec.describe DossierCloneConcern do end context 'with old revision having repetition' do - let(:added_champ) { nil } let(:removed_champ) { dossier.champs.find(&:repetition?) } - let(:updated_champ) { nil } before do dossier.champs.each do |champ| diff --git a/spec/models/concerns/dossier_rebase_concern_spec.rb b/spec/models/concerns/dossier_rebase_concern_spec.rb index 5b4c1704a..93a1e7c43 100644 --- a/spec/models/concerns/dossier_rebase_concern_spec.rb +++ b/spec/models/concerns/dossier_rebase_concern_spec.rb @@ -349,7 +349,7 @@ describe DossierRebaseConcern do # Add two rows then remove previous to last row in order to create a "hole" in the sequence repetition_champ.add_row(updated_by: 'test') repetition_champ.add_row(updated_by: 'test') - repetition_champ.champs.where(row_id: repetition_champ.row_ids[-2]).destroy_all + repetition_champ.dossier.champs.where(row_id: repetition_champ.row_ids[-2]).destroy_all dossier.reload end @@ -728,7 +728,7 @@ describe DossierRebaseConcern do parent.update(type_champ: :integer_number) end - it { expect { subject }.to change { dossier.project_champs_public.first.champs.count }.from(2).to(0) } + it { expect { subject }.to change { dossier.champs.filter(&:child?).count }.from(2).to(0) } it { expect { subject }.to change { Champ.count }.from(3).to(1) } end end diff --git a/spec/models/dossier_preloader_spec.rb b/spec/models/dossier_preloader_spec.rb index fb2fadda7..692aa7881 100644 --- a/spec/models/dossier_preloader_spec.rb +++ b/spec/models/dossier_preloader_spec.rb @@ -12,7 +12,7 @@ describe DossierPreloader do let(:dossier) { create(:dossier, procedure: procedure) } let(:repetition) { subject.project_champs_public.second } let(:repetition_optional) { subject.project_champs_public.third } - let(:first_child) { subject.project_champs_public.second.champs.first } + let(:first_child) { repetition.rows.first.first } describe 'all' do subject { DossierPreloader.load_one(dossier, pj_template: true) } @@ -40,9 +40,8 @@ describe DossierPreloader do expect(subject.champs.find(&:public?).conditional?).to eq(false) expect(subject.project_champs_public.first.conditional?).to eq(false) - expect(first_child.parent).to eq(repetition) - expect(repetition.champs.first).to eq(first_child) - expect(repetition_optional.champs).to be_empty + expect(repetition.rows.first.first).to eq(first_child) + expect(repetition_optional.row_ids).to be_empty end expect(count).to eq(0) diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb index 1c0979043..aa97ea78e 100644 --- a/spec/services/pieces_justificatives_service_spec.rb +++ b/spec/services/pieces_justificatives_service_spec.rb @@ -52,8 +52,8 @@ describe PiecesJustificativesService do end context 'with a repetition' do - let(:first_champ) { repetition(dossier).champs.first } - let(:second_champ) { repetition(dossier).champs.second } + let(:first_champ) { repetition(dossier).rows.first.first } + let(:second_champ) { repetition(dossier).rows.second.first } before do repetition(dossier).add_row(updated_by: 'test') @@ -65,8 +65,8 @@ describe PiecesJustificativesService do end it do - first_child_attachments = attachments(repetition(dossier).champs.first) - second_child_attachments = attachments(repetition(dossier).champs.second) + first_child_attachments = attachments(repetition(dossier).rows.first.first) + second_child_attachments = attachments(repetition(dossier).rows.second.first) expect(export_template).to receive(:attachment_path) .with(dossier, first_child_attachments.first, index: 0, row_index: 0, champ: first_champ) diff --git a/spec/services/procedure_export_service_zip_spec.rb b/spec/services/procedure_export_service_zip_spec.rb index 44602784e..13050d011 100644 --- a/spec/services/procedure_export_service_zip_spec.rb +++ b/spec/services/procedure_export_service_zip_spec.rb @@ -16,11 +16,11 @@ describe ProcedureExportService do attach_file_to_champ(pj_champ(dossier)) repetition(dossier).add_row(updated_by: 'test') - attach_file_to_champ(repetition(dossier).champs.first) - attach_file_to_champ(repetition(dossier).champs.first) + attach_file_to_champ(repetition(dossier).rows.first.first) + attach_file_to_champ(repetition(dossier).rows.first.first) repetition(dossier).add_row(updated_by: 'test') - attach_file_to_champ(repetition(dossier).champs.second) + attach_file_to_champ(repetition(dossier).rows.second.first) end allow_any_instance_of(ActiveStorage::Attachment).to receive(:url).and_return("https://opengraph.githubassets.com/d0e7862b24d8026a3c03516d865b28151eb3859029c6c6c2e86605891fbdcd7a/socketry/async-io") diff --git a/spec/tasks/maintenance/rescue_dossier_with_invalid_repetition_task_spec.rb b/spec/tasks/maintenance/rescue_dossier_with_invalid_repetition_task_spec.rb deleted file mode 100644 index 4d7a75ac9..000000000 --- a/spec/tasks/maintenance/rescue_dossier_with_invalid_repetition_task_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require "rails_helper" - -module Maintenance - RSpec.describe RescueDossierWithInvalidRepetitionTask do - describe "#process" do - let(:procedure) { create(:procedure, types_de_champ_public:) } - let(:types_de_champ_public) do - [ - { type: :repetition, children: [{ type: :text, mandatory: true }] }, - { type: :checkbox } - ] - end - let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } - let(:invalid_champ) { dossier.champs.find(&:checkbox?) } - - # reproduce bad data - before { invalid_champ.update!(row_id: dossier.champs[1].row_id) } - - it "dissociate champ having a row_id without a parent_id" do - expect { described_class.process(dossier.id) } - .to change { Champ.exists?(invalid_champ.id) }.from(true).to(false) - end - end - end -end