diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 7d4397392..29a924ddf 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -105,7 +105,7 @@ class Procedure < ApplicationRecord if brouillon? TypeDeChamp.fillable .joins(:revision_types_de_champ) - .where(revision_types_de_champ: { revision: draft_revision }) + .where(revision_types_de_champ: { revision: draft_revision, parent_id: nil }) .order(:private, :position) else # fetch all type_de_champ.stable_id for all the revisions expect draft @@ -114,12 +114,14 @@ class Procedure < ApplicationRecord .joins(:revisions) .where(procedure_revisions: { procedure_id: id }) .where.not(procedure_revisions: { id: draft_revision_id }) + .where(revision_types_de_champ: { parent_id: nil }) .group(:stable_id) .select('MAX(types_de_champ.id)') # fetch the more recent procedure_revision_types_de_champ # which includes recents_ids recents_prtdc = ProcedureRevisionTypeDeChamp + .root .where(type_de_champ_id: recent_ids) .where.not(revision_id: draft_revision_id) .group(:type_de_champ_id) @@ -139,7 +141,10 @@ class Procedure < ApplicationRecord TypeDeChamp.root .public_only .fillable - .where(revision: revisions - [draft_revision]) + .joins(:revisions) + .where(procedure_revisions: { procedure_id: id }) + .where.not(procedure_revisions: { id: draft_revision_id }) + .where(revision_types_de_champ: { parent_id: nil }) .order(:created_at) .uniq end @@ -152,7 +157,10 @@ class Procedure < ApplicationRecord TypeDeChamp.root .private_only .fillable - .where(revision: revisions - [draft_revision]) + .joins(:revisions) + .where(procedure_revisions: { procedure_id: id }) + .where.not(procedure_revisions: { id: draft_revision_id }) + .where(revision_types_de_champ: { parent_id: nil }) .order(:created_at) .uniq end @@ -471,7 +479,9 @@ class Procedure < ApplicationRecord procedure.save procedure.draft_types_de_champ.update_all(revision_id: procedure.draft_revision.id) procedure.draft_types_de_champ_private.update_all(revision_id: procedure.draft_revision.id) - TypeDeChamp.where(parent: procedure.draft_types_de_champ.repetition + procedure.draft_types_de_champ_private.repetition).update_all(revision_id: procedure.draft_revision.id) + types_de_champ_in_repetition = TypeDeChamp.where(parent: procedure.draft_types_de_champ.repetition + procedure.draft_types_de_champ_private.repetition) + types_de_champ_in_repetition.update_all(revision_id: procedure.draft_revision.id) + types_de_champ_in_repetition.each(&:migrate_parent!) if is_different_admin || from_library procedure.draft_types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) } diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index 25865fc96..fbef56bdb 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -14,8 +14,8 @@ class ProcedureRevision < ApplicationRecord has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id - has_many :revision_types_de_champ, -> { public_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision - has_many :revision_types_de_champ_private, -> { private_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision + has_many :revision_types_de_champ, -> { root.public_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision + has_many :revision_types_de_champ_private, -> { root.private_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision has_many :types_de_champ, through: :revision_types_de_champ, source: :type_de_champ has_many :types_de_champ_private, through: :revision_types_de_champ_private, source: :type_de_champ @@ -23,6 +23,8 @@ class ProcedureRevision < ApplicationRecord has_one :draft_procedure, -> { with_discarded }, class_name: 'Procedure', foreign_key: :draft_revision_id, dependent: :nullify, inverse_of: :draft_revision has_one :published_procedure, -> { with_discarded }, class_name: 'Procedure', foreign_key: :published_revision_id, dependent: :nullify, inverse_of: :published_revision + scope :ordered, -> { order(:created_at) } + def build_champs types_de_champ.map(&:build_champ) end @@ -39,7 +41,7 @@ class ProcedureRevision < ApplicationRecord .types_de_champ .tap do |types_de_champ| params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0 - end.create(params) + end.create(params).migrate_parent! elsif params[:private] types_de_champ_private.create(params) else @@ -66,7 +68,9 @@ class ProcedureRevision < ApplicationRecord repetition_type_de_champ = find_or_clone_type_de_champ(id).parent move_type_de_champ_hash(repetition_type_de_champ.types_de_champ.to_a, type_de_champ, position).each do |(id, position)| - repetition_type_de_champ.types_de_champ.find(id).update!(order_place: position) + type_de_champ = repetition_type_de_champ.types_de_champ.find(id) + type_de_champ.update!(order_place: position) + type_de_champ.revision_type_de_champ&.update!(position: position) end elsif type_de_champ.private? move_type_de_champ_hash(types_de_champ_private.to_a, type_de_champ, position).each do |(id, position)| @@ -294,6 +298,7 @@ class ProcedureRevision < ApplicationRecord end cloned_type_de_champ.revision = self association.update!(type_de_champ: cloned_type_de_champ) + cloned_type_de_champ.types_de_champ.each(&:migrate_parent!) cloned_type_de_champ end diff --git a/app/models/procedure_revision_type_de_champ.rb b/app/models/procedure_revision_type_de_champ.rb index 6859d1884..ab26a544d 100644 --- a/app/models/procedure_revision_type_de_champ.rb +++ b/app/models/procedure_revision_type_de_champ.rb @@ -6,6 +6,7 @@ # position :integer not null # created_at :datetime not null # updated_at :datetime not null +# parent_id :bigint # revision_id :bigint not null # type_de_champ_id :bigint not null # @@ -13,7 +14,11 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord belongs_to :revision, class_name: 'ProcedureRevision' belongs_to :type_de_champ + belongs_to :parent, class_name: 'ProcedureRevisionTypeDeChamp', optional: true + has_many :revision_types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: :parent, dependent: :destroy + scope :root, -> { where(parent: nil) } scope :ordered, -> { order(:position) } + scope :revision_ordered, -> { order(:revision_id) } scope :public_only, -> { joins(:type_de_champ).where(types_de_champ: { private: false }) } scope :private_only, -> { joins(:type_de_champ).where(types_de_champ: { private: true }) } diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 46ee9f2b2..930fabff9 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -2,19 +2,20 @@ # # Table name: types_de_champ # -# id :integer not null, primary key -# description :text -# libelle :string -# mandatory :boolean default(FALSE) -# options :jsonb -# order_place :integer -# private :boolean default(FALSE), not null -# type_champ :string -# created_at :datetime -# updated_at :datetime -# parent_id :bigint -# revision_id :bigint -# stable_id :bigint +# id :integer not null, primary key +# description :text +# libelle :string +# mandatory :boolean default(FALSE) +# migrated_parent :boolean +# options :jsonb +# order_place :integer +# private :boolean default(FALSE), not null +# type_champ :string +# created_at :datetime +# updated_at :datetime +# parent_id :bigint +# revision_id :bigint +# stable_id :bigint # class TypeDeChamp < ApplicationRecord enum type_champs: { @@ -59,8 +60,9 @@ class TypeDeChamp < ApplicationRecord has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy store_accessor :options, :cadastres, :old_pj, :drop_down_options, :skip_pj_validation, :skip_content_type_pj_validation, :drop_down_secondary_libelle, :drop_down_secondary_description, :drop_down_other - has_many :revision_types_de_champ, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ - has_many :revisions, through: :revision_types_de_champ + has_many :revision_types_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ + has_one :revision_type_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: false + has_many :revisions, -> { ordered }, through: :revision_types_de_champ delegate :tags_for_template, :libelle_for_export, to: :dynamic_type @@ -373,6 +375,17 @@ class TypeDeChamp < ApplicationRecord end end + def migrate_parent! + if parent_id.present? && migrated_parent.nil? + ProcedureRevisionTypeDeChamp.create(parent: parent.revision_type_de_champ, + type_de_champ: self, + revision_id: parent.revision_type_de_champ.revision_id, + position: order_place) + update_column(:migrated_parent, true) + end + self + end + private def parse_drop_down_list_value(value) diff --git a/db/migrate/20210630101808_add_parent_id_to_procedure_revision_type_de_champ.rb b/db/migrate/20210630101808_add_parent_id_to_procedure_revision_type_de_champ.rb new file mode 100644 index 000000000..66851c8da --- /dev/null +++ b/db/migrate/20210630101808_add_parent_id_to_procedure_revision_type_de_champ.rb @@ -0,0 +1,5 @@ +class AddParentIdToProcedureRevisionTypeDeChamp < ActiveRecord::Migration[6.1] + def change + add_belongs_to :procedure_revision_types_de_champ, :parent, index: true, foreign_key: { to_table: :procedure_revision_types_de_champ } + end +end diff --git a/db/migrate/20211124134220_add_migrated_parent_to_types_de_champ.rb b/db/migrate/20211124134220_add_migrated_parent_to_types_de_champ.rb new file mode 100644 index 000000000..3c2e2b50b --- /dev/null +++ b/db/migrate/20211124134220_add_migrated_parent_to_types_de_champ.rb @@ -0,0 +1,5 @@ +class AddMigratedParentToTypesDeChamp < ActiveRecord::Migration[6.1] + def change + add_column :types_de_champ, :migrated_parent, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 2ea7addb4..75c1a7327 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_12_01_135804) do +ActiveRecord::Schema.define(version: 2021_12_02_135804) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -581,6 +581,8 @@ ActiveRecord::Schema.define(version: 2021_12_01_135804) do t.integer "position", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.bigint "parent_id" + t.index ["parent_id"], name: "index_procedure_revision_types_de_champ_on_parent_id" t.index ["revision_id"], name: "index_procedure_revision_types_de_champ_on_revision_id" t.index ["type_de_champ_id"], name: "index_procedure_revision_types_de_champ_on_type_de_champ_id" end @@ -766,6 +768,7 @@ ActiveRecord::Schema.define(version: 2021_12_01_135804) do t.bigint "stable_id" t.bigint "parent_id" t.bigint "revision_id" + t.boolean "migrated_parent" t.index ["parent_id"], name: "index_types_de_champ_on_parent_id" t.index ["private"], name: "index_types_de_champ_on_private" t.index ["revision_id"], name: "index_types_de_champ_on_revision_id" @@ -865,6 +868,7 @@ ActiveRecord::Schema.define(version: 2021_12_01_135804) do add_foreign_key "initiated_mails", "procedures" add_foreign_key "merge_logs", "users" add_foreign_key "procedure_presentations", "assign_tos" + add_foreign_key "procedure_revision_types_de_champ", "procedure_revision_types_de_champ", column: "parent_id" add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id" add_foreign_key "procedure_revision_types_de_champ", "types_de_champ" add_foreign_key "procedure_revisions", "procedures" diff --git a/lib/tasks/deployment/20210630101910_migrate_type_de_champ_parent.rake b/lib/tasks/deployment/20210630101910_migrate_type_de_champ_parent.rake new file mode 100644 index 000000000..2433bda73 --- /dev/null +++ b/lib/tasks/deployment/20210630101910_migrate_type_de_champ_parent.rake @@ -0,0 +1,23 @@ +namespace :after_party do + desc 'Deployment task: migrate_type_de_champ_parent' + task migrate_type_de_champ_parent: :environment do + puts "Running deploy task 'migrate_type_de_champ_parent'" + + types_de_champ = TypeDeChamp + .where.not(parent_id: nil) + .where(migrated_parent: nil) + .includes(:revisions, parent: :revision_type_de_champ) + + progress = ProgressReport.new(types_de_champ.count) + types_de_champ.find_each do |type_de_champ| + type_de_champ.migrate_parent! + progress.inc + 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 +end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 146c98926..c9414ceae 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -437,7 +437,7 @@ describe Procedure do end TypeDeChamp.where(parent: procedure.draft_types_de_champ.repetition).zip(TypeDeChamp.where(parent: subject.draft_types_de_champ.repetition)).each do |ptc, stc| - expect(stc).to have_same_attributes_as(ptc, except: ["revision_id", "parent_id"]) + expect(stc).to have_same_attributes_as(ptc, except: ["revision_id", "parent_id", "migrated_parent"]) expect(stc.revision).to eq(subject.draft_revision) end @@ -447,7 +447,7 @@ describe Procedure do end TypeDeChamp.where(parent: procedure.draft_types_de_champ_private.repetition).zip(TypeDeChamp.where(parent: subject.draft_types_de_champ_private.repetition)).each do |ptc, stc| - expect(stc).to have_same_attributes_as(ptc, except: ["revision_id", "parent_id"]) + expect(stc).to have_same_attributes_as(ptc, except: ["revision_id", "parent_id", "migrated_parent"]) expect(stc.revision).to eq(subject.draft_revision) end