163 lines
4.7 KiB
Ruby
163 lines
4.7 KiB
Ruby
module DossierRebaseConcern
|
|
extend ActiveSupport::Concern
|
|
|
|
def rebase!
|
|
if can_rebase?
|
|
transaction do
|
|
rebase
|
|
end
|
|
end
|
|
end
|
|
|
|
def rebase_later
|
|
DossierRebaseJob.perform_later(self)
|
|
end
|
|
|
|
def can_rebase?
|
|
revision != procedure.published_revision &&
|
|
(brouillon? || accepted_en_construction_changes? || accepted_en_instruction_changes?)
|
|
end
|
|
|
|
def pending_changes
|
|
revision.compare(procedure.published_revision)
|
|
end
|
|
|
|
private
|
|
|
|
def accepted_en_construction_changes?
|
|
en_construction? && pending_changes.all? { |change| accepted_change?(change) }
|
|
end
|
|
|
|
def accepted_en_instruction_changes?
|
|
en_instruction? && pending_changes.all? { |change| accepted_change?(change) }
|
|
end
|
|
|
|
def accepted_change?(change)
|
|
return true if change[:private]
|
|
return true if change[:op].in?([:remove, :move])
|
|
return !change[:mandatory] if change[:op] == :add
|
|
|
|
case change[:attribute]
|
|
when :drop_down_options
|
|
(change[:from] - change[:to]).empty?
|
|
when :drop_down_other
|
|
!change[:from] && change[:to]
|
|
when :mandatory
|
|
change[:from] && !change[:to]
|
|
when :type_champ, :condition
|
|
false
|
|
else
|
|
true
|
|
end
|
|
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(:type_de_champ, :parent)
|
|
.index_by(&:stable_id)
|
|
|
|
changes_by_op = pending_changes
|
|
.filter { |change| change[:model] == :type_de_champ }
|
|
.group_by { |change| change[:op] }
|
|
.tap { |h| h.default = [] }
|
|
|
|
# add champ
|
|
changes_by_op[:add]
|
|
.map { |change| change[:stable_id] }
|
|
.map { |stable_id| target_coordinates_by_stable_id[stable_id] }
|
|
.each { |coordinate| add_new_champs_for_revision(coordinate) }
|
|
|
|
# remove champ
|
|
changes_by_op[:remove]
|
|
.each { |change| delete_champs_for_revision(change[:stable_id]) }
|
|
|
|
changes_by_op[:update]
|
|
.map { |change| [change, Champ.joins(:type_de_champ).where(dossier: self, type_de_champ: { stable_id: change[:stable_id] })] }
|
|
.each { |change, champs| apply(change, champs) }
|
|
|
|
# due to repetition tdc clone on update or erase
|
|
# we must reassign tdc to the latest version
|
|
Champ
|
|
.includes(:type_de_champ)
|
|
.where(dossier: self)
|
|
.map { |c| [c, target_coordinates_by_stable_id[c.stable_id].type_de_champ] }
|
|
.each { |c, target_tdc| c.update_columns(type_de_champ_id: target_tdc.id, rebased_at: Time.zone.now) }
|
|
|
|
# update dossier revision
|
|
self.update_column(:revision_id, target_revision.id)
|
|
end
|
|
|
|
def apply(change, champs)
|
|
case change[:attribute]
|
|
when :type_champ
|
|
champs.each { |champ| purge_piece_justificative_file(champ) }
|
|
GeoArea.where(champ: champs).destroy_all
|
|
Etablissement.where(champ: champs).destroy_all
|
|
|
|
{
|
|
type: "Champs::#{change[:to].classify}Champ",
|
|
value: nil,
|
|
value_json: nil,
|
|
external_id: nil,
|
|
data: nil
|
|
}
|
|
when :drop_down_options
|
|
{ value: nil }
|
|
when :carte_layers
|
|
# if we are removing cadastres layer, we need to remove cadastre geo areas
|
|
if change[:from].include?(:cadastres) && !change[:to].include?(:cadastres)
|
|
champs.each { |champ| champ.cadastres.each(&:destroy) }
|
|
end
|
|
|
|
nil
|
|
end
|
|
&.then { |update_params| champs.update_all(update_params) }
|
|
end
|
|
|
|
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
|
|
champs_repetition = Champ
|
|
.includes(:champs, :type_de_champ)
|
|
.where(dossier: self, type_de_champ: { stable_id: parent_stable_id })
|
|
|
|
champs_repetition.each do |champ_repetition|
|
|
champ_repetition.champs.map(&:row).uniq.each do |row|
|
|
create_champ(target_coordinate, champ_repetition, row: row)
|
|
end
|
|
end
|
|
else
|
|
create_champ(target_coordinate, self)
|
|
end
|
|
end
|
|
|
|
def create_champ(target_coordinate, parent, row: nil)
|
|
params = { revision: target_coordinate.revision }
|
|
params[:row] = row if row
|
|
champ = target_coordinate
|
|
.type_de_champ
|
|
.build_champ(params)
|
|
if parent.is_a?(Dossier)
|
|
parent.champs_public << champ
|
|
else
|
|
parent.champs << champ
|
|
end
|
|
end
|
|
|
|
def delete_champs_for_revision(stable_id)
|
|
Champ
|
|
.joins(:type_de_champ)
|
|
.where(dossier: self, types_de_champ: { stable_id: stable_id })
|
|
.destroy_all
|
|
end
|
|
|
|
def purge_piece_justificative_file(champ)
|
|
ActiveStorage::Attachment.where(id: champ.piece_justificative_file.ids).delete_all
|
|
end
|
|
end
|