refactor(repetition): remove parent_id
This commit is contained in:
parent
e7080c1ad1
commit
bd32f5693d
25 changed files with 72 additions and 222 deletions
|
@ -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
|
||||
|
|
|
@ -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:)
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue