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

132 lines
4.1 KiB
Ruby
Raw Normal View History

module DossierChampsConcern
extend ActiveSupport::Concern
def champs_for_revision(scope: nil, root: false)
champs_index = champs.group_by(&:stable_id)
# Due to some bad data we can have multiple copies of the same champ. Ignore extra copy.
.transform_values { _1.sort_by(&:id).uniq(&:row_id) }
if scope.is_a?(TypeDeChamp)
revision
.children_of(scope)
.flat_map { champs_index[_1.stable_id] || [] }
.filter(&:child?) # TODO: remove once bad data (child champ without a row id) is cleaned
else
revision
.types_de_champ_for(scope:, root:)
.flat_map { champs_index[_1.stable_id] || [] }
end
end
# Get all the champs values for the types de champ in the final list.
# Dossier might not have corresponding champ display nil.
# To do so, we build a virtual champ when there is no value so we can call for_export with all indexes
def champs_for_export(types_de_champ, row_id = nil)
types_de_champ.flat_map do |type_de_champ|
champ = champ_for_export(type_de_champ, row_id)
type_de_champ.libelles_for_export.map do |(libelle, path)|
[libelle, TypeDeChamp.champ_value_for_export(type_de_champ.type_champ, champ, path)]
end
end
end
def project_champ(type_de_champ, row_id)
champ = champs_by_public_id[type_de_champ.public_id(row_id)]
if champ.nil?
type_de_champ.build_champ(dossier: self, row_id:)
else
champ
end
end
def find_type_de_champ_by_stable_id(stable_id, scope = nil)
case scope
when :public
revision.types_de_champ.public_only
when :private
revision.types_de_champ.private_only
else
revision.types_de_champ
end.find_by!(stable_id:)
end
def champs_for_prefill(stable_ids)
revision
.types_de_champ
.filter { _1.stable_id.in?(stable_ids) }
.filter { !revision.child?(_1) }
.map { champ_for_update(_1, nil) }
end
def champ_for_update(type_de_champ, row_id)
champ, attributes = champ_with_attributes_for_update(type_de_champ, row_id)
champ.assign_attributes(attributes)
champ
end
def update_champs_attributes(attributes, scope)
# TODO: remove after one deploy
if attributes.present? && attributes.values.filter { _1.key?(:with_public_id) }.empty?
assign_attributes("champs_#{scope}_all_attributes".to_sym => attributes)
@champs_by_public_id = nil
return
end
champs_attributes = attributes.to_h.map do |public_id, attributes|
champ_attributes_by_public_id(public_id, attributes, scope)
end
assign_attributes(champs_attributes:)
end
private
def champs_by_public_id
@champs_by_public_id ||= champs.sort_by(&:id).index_by(&:public_id)
end
def champ_for_export(type_de_champ, row_id)
champ = champs_by_public_id[type_de_champ.public_id(row_id)]
if champ.blank? || !champ.visible?
nil
else
champ
end
end
def champ_attributes_by_public_id(public_id, attributes, scope)
stable_id, row_id = public_id.split('-')
type_de_champ = find_type_de_champ_by_stable_id(stable_id, scope)
champ_with_attributes_for_update(type_de_champ, row_id).last.merge(attributes)
end
def champ_with_attributes_for_update(type_de_champ, row_id)
attributes = type_de_champ.params_for_champ
# TODO: Once we have the right index in place, we should change this to use `create_or_find_by` instead of `find_or_create_by`
champ = champs
.create_with(type_de_champ:, **attributes)
.find_or_create_by!(stable_id: type_de_champ.stable_id, row_id:)
attributes[:id] = champ.id
# Needed when a revision change the champ type in this case, we reset the champ data
if champ.type != attributes[:type]
attributes[:value] = nil
attributes[:value_json] = nil
attributes[:external_id] = nil
attributes[:data] = nil
end
parent = revision.parent_of(type_de_champ)
if parent.present?
attributes[:parent] = champs.find { _1.type_de_champ_id == parent.id }
else
attributes[:parent] = nil
end
@champs_by_public_id = nil
[champ, attributes]
end
end