demarches-normaliennes/app/models/concerns/dossier_rebase_concern.rb

107 lines
3 KiB
Ruby

# frozen_string_literal: true
module DossierRebaseConcern
extend ActiveSupport::Concern
def rebase!(force: false)
ProcedureRevisionPreloader.new([procedure.published_revision, revision].compact).all
return if procedure.published_revision.blank?
if force || can_rebase?
transaction do
rebase
end
end
end
def rebase_later
DossierRebaseJob.perform_later(self)
end
def can_rebase?
procedure.published_revision.present? && revision != procedure.published_revision &&
(brouillon? || accepted_en_construction_changes? || accepted_en_instruction_changes?)
end
def pending_changes
procedure.published_revision.present? ? revision.compare_types_de_champ(procedure.published_revision) : []
end
def can_rebase_mandatory_change?(stable_id)
!champs.filter { _1.stable_id == stable_id }.any?(&:blank?)
end
def can_rebase_drop_down_options_change?(stable_id, options)
!champs.filter { _1.stable_id == stable_id }.any? { _1.in?(options) }
end
private
def accepted_en_construction_changes?
en_construction? && pending_changes.all? { _1.can_rebase?(self) }
end
def accepted_en_instruction_changes?
en_instruction? && pending_changes.all? { _1.can_rebase?(self) }
end
def rebase
# revision we are rebasing to
target_revision = procedure.published_revision
# index published types de champ coordinates by stable_id
target_coordinates_by_stable_id = target_revision
.revision_types_de_champ
.includes(:parent)
.index_by(&:stable_id)
changes_by_op = pending_changes
.group_by(&:op)
.tap { _1.default = [] }
champs_by_stable_id = champs
.group_by(&:stable_id)
.transform_values { Champ.where(id: _1) }
.tap { _1.default = Champ.none }
# remove champ
changes_by_op[:remove].each { champs_by_stable_id[_1.stable_id].destroy_all }
# update champ
changes_by_op[:update].each { champs_by_stable_id[_1.stable_id].update_all(rebased_at: Time.zone.now) }
# update dossier revision
update_column(:revision_id, target_revision.id)
# add champ (after changing dossier revision to avoid errors)
changes_by_op[:add]
.map { target_coordinates_by_stable_id[_1.stable_id] }
.each { add_new_champs_for_revision(_1) }
end
def add_new_champs_for_revision(target_coordinate)
if target_coordinate.child?
row_ids = repetition_row_ids(target_coordinate.parent.type_de_champ)
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)
end
end
def create_champ(target_coordinate, row_id: nil)
self.champs << target_coordinate
.type_de_champ
.build_champ(rebased_at: Time.zone.now, row_id:)
end
def purge_piece_justificative_file(champ)
ActiveStorage::Attachment.where(id: champ.piece_justificative_file.ids).delete_all
end
end