Merge pull request #10234 from tchak/type-de-champ-paths

feat(champ): add paths to type_de_champ
This commit is contained in:
Paul Chavard 2024-04-08 08:07:30 +00:00 committed by GitHub
commit c5c671f391
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 364 additions and 185 deletions

View file

@ -110,8 +110,8 @@ class Champ < ApplicationRecord
value.present? ? value.to_s : ''
end
def for_export
value.presence
def for_export(path = :value)
path == :value ? value.presence : nil
end
def for_api
@ -122,8 +122,8 @@ class Champ < ApplicationRecord
to_s
end
def for_tag
value.present? ? value.to_s : ''
def for_tag(path = :value)
path == :value && value.present? ? value.to_s : ''
end
def main_value_name

View file

@ -42,12 +42,26 @@ class Champs::AddressChamp < Champs::TextChamp
address_label.presence || ''
end
def for_tag
address_label
def for_tag(path = :value)
case path
when :value
address_label
when :departement
departement_code_and_name || ''
when :commune
commune_name || ''
end
end
def for_export
value.present? ? address_label : nil
def for_export(path = :value)
case path
when :value
value.present? ? address_label : nil
when :departement
departement_code_and_name
when :commune
commune_name
end
end
def for_api

View file

@ -25,11 +25,11 @@ class Champs::BooleanChamp < Champ
processed_value
end
def for_tag
def for_tag(path = :value)
processed_value
end
def for_export
def for_export(path = :value)
processed_value
end

View file

@ -79,7 +79,7 @@ class Champs::CarteChamp < Champ
nil
end
def for_export
def for_export(path = :value)
geo_areas.map(&:label).join("\n")
end

View file

@ -1,5 +1,5 @@
class Champs::CheckboxChamp < Champs::BooleanChamp
def for_export
def for_export(path = :value)
true? ? 'on' : 'off'
end

View file

@ -2,8 +2,26 @@ class Champs::CommuneChamp < Champs::TextChamp
store_accessor :value_json, :code_departement, :code_postal, :code_region
before_save :on_codes_change, if: :should_refresh_after_code_change?
def for_export
[to_s, code? ? code : '', departement? ? departement_code_and_name : '']
def for_export(path = :value)
case path
when :value
to_s
when :departement
departement_code_and_name || ''
when :code
code || ''
end
end
def for_tag(path = :value)
case path
when :value
to_s
when :departement
departement_code_and_name || ''
when :code
code || ''
end
end
def departement_name

View file

@ -12,7 +12,9 @@ class Champs::DateChamp < Champ
value.presence || "" # old dossiers can have not parseable dates
end
alias for_tag to_s
def for_tag(path = :value)
to_s if path == :value
end
private

View file

@ -10,7 +10,7 @@ class Champs::DatetimeChamp < Champ
value.present? ? I18n.l(Time.zone.parse(value)) : ""
end
def for_tag
def for_tag(path = :value)
value.present? ? I18n.l(Time.zone.parse(value)) : ""
end

View file

@ -16,7 +16,7 @@ class Champs::DecimalNumberChamp < Champ
}
}, if: -> { validate_champ_value? || validation_context == :prefill }
def for_export
def for_export(path = :value)
processed_value
end

View file

@ -5,16 +5,26 @@ class Champs::DepartementChamp < Champs::TextChamp
validate :external_id_in_departement_codes, unless: -> { external_id.nil? }
before_save :store_code_region
def for_export
[name, code]
def for_export(path = :value)
case path
when :code
code
when :value
name
end
end
def to_s
formatted_value
end
def for_tag
formatted_value
def for_tag(path = :value)
case path
when :code
code
when :value
formatted_value
end
end
def for_api

View file

@ -8,8 +8,26 @@ class Champs::EpciChamp < Champs::TextChamp
validate :external_id_in_departement_epci_codes, unless: -> { code_departement.nil? || external_id.nil? }
validate :value_in_departement_epci_names, unless: -> { code_departement.nil? || external_id.nil? || value.nil? }
def for_export
[value, code, "#{code_departement} #{departement_name}"]
def for_export(path = :value)
case path
when :value
value
when :code
code
when :departement
departement_code_and_name
end
end
def for_tag(path = :value)
case path
when :value
value
when :code
code
when :departement
departement_code_and_name
end
end
def departement_name
@ -62,6 +80,12 @@ class Champs::EpciChamp < Champs::TextChamp
end
end
def departement_code_and_name
if departement?
"#{code_departement} #{departement_name}"
end
end
def code_departement_input_id
"#{input_id}-code_departement"
end

View file

@ -9,7 +9,7 @@ class Champs::IntegerNumberChamp < Champ
}
}, if: -> { validate_champ_value? || validation_context == :prefill }
def for_export
def for_export(path = :value)
processed_value
end

View file

@ -41,12 +41,26 @@ class Champs::LinkedDropDownListChamp < Champ
value.present? ? [primary_value, secondary_value].filter(&:present?).join(' / ') : ""
end
def for_tag
value.present? ? [primary_value, secondary_value].filter(&:present?).join(' / ') : ""
def for_tag(path = :value)
case path
when :primary
primary_value
when :secondary
secondary_value
when :value
value.present? ? [primary_value, secondary_value].filter(&:present?).join(' / ') : ""
end
end
def for_export
value.present? ? "#{primary_value || ''};#{secondary_value || ''}" : nil
def for_export(path = :value)
case path
when :primary
primary_value
when :secondary
secondary_value
when :value
value.present? ? "#{primary_value || ''};#{secondary_value || ''}" : nil
end
end
def for_api

View file

@ -24,11 +24,11 @@ class Champs::MultipleDropDownListChamp < Champ
selected_options.join(', ')
end
def for_tag
def for_tag(path = :value)
selected_options.join(', ')
end
def for_export
def for_export(path = :value)
value.present? ? selected_options.join(', ') : nil
end

View file

@ -11,16 +11,26 @@ class Champs::PaysChamp < Champs::TextChamp
validates :value, inclusion: APIGeoService.countries.pluck(:name), allow_nil: false, allow_blank: false
end
def for_export
[name, code]
def for_export(path = :value)
case path
when :code
code
when :value
name
end
end
def to_s
name
end
def for_tag
name
def for_tag(path = :value)
case path
when :code
code
when :value
name
end
end
def selected

View file

@ -26,7 +26,7 @@ class Champs::PieceJustificativeChamp < Champ
piece_justificative_file.blank?
end
def for_export
def for_export(path = :value)
piece_justificative_file.map { _1.filename.to_s }.join(', ')
end

View file

@ -3,8 +3,22 @@ class Champs::RegionChamp < Champs::TextChamp
validate :value_in_region_names, unless: -> { value.nil? }
validate :external_id_in_region_codes, unless: -> { external_id.nil? }
def for_export
[name, code]
def for_export(path = :value)
case path
when :value
name
when :code
code
end
end
def for_tag(path = :value)
case path
when :value
name
when :code
code
end
end
def selected

View file

@ -1,6 +1,5 @@
class Champs::RepetitionChamp < Champ
accepts_nested_attributes_for :champs
delegate :libelle_for_export, to: :type_de_champ
def rows
dossier
@ -34,7 +33,7 @@ class Champs::RepetitionChamp < Champ
# The user cannot enter any information here so it doesnt make much sense to search
end
def for_tag
def for_tag(path = :value)
([libelle] + rows.map do |champs|
champs.map do |champ|
"#{champ.libelle} : #{champ}"

View file

@ -16,7 +16,7 @@ class Champs::RNAChamp < Champ
title.present? ? "#{value} (#{title})" : value
end
def for_export
def for_export(path = :value)
identifier
end

View file

@ -25,11 +25,33 @@ class Champs::RNFChamp < Champ
rnf_id.blank?
end
def for_export
if address.present?
[rnf_id, title, address['label'], address['cityCode'], departement_code_and_name]
else
[rnf_id, nil, nil, nil, nil]
def for_export(path = :value)
case path
when :value
rnf_id
when :departement
departement_code_and_name
when :code_insee
commune&.fetch(:code)
when :address
full_address
when :nom
title
end
end
def for_tag(path = :value)
case path
when :value
rnf_id
when :departement
departement_code_and_name || ''
when :code_insee
commune&.fetch(:code) || ''
when :address
full_address || ''
when :nom
title || ''
end
end
@ -59,7 +81,7 @@ class Champs::RNFChamp < Champ
def commune_name
if departement?
"#{APIGeoService.commune_name(department_code, address['cityCode'])} (#{address['postalCode']})"
"#{APIGeoService.commune_name(code_departement, address['cityCode'])} (#{address['postalCode']})"
end
end
@ -69,8 +91,8 @@ class Champs::RNFChamp < Champ
city_name = address['cityName']
postal_code = address['postalCode']
commune_name = APIGeoService.commune_name(department_code, city_code)
commune_code = APIGeoService.commune_code(department_code, city_name)
commune_name = APIGeoService.commune_name(code_departement, city_code)
commune_code = APIGeoService.commune_code(code_departement, city_name)
if commune_name.present?
{

View file

@ -1,5 +1,5 @@
class Champs::TextareaChamp < Champs::TextChamp
def for_export
def for_export(path = :value)
value.present? ? ActionView::Base.full_sanitizer.sanitize(value) : nil
end

View file

@ -20,7 +20,7 @@ class Champs::TitreIdentiteChamp < Champ
piece_justificative_file.blank?
end
def for_export
def for_export(path = :value)
piece_justificative_file.attached? ? "présent" : "absent"
end

View file

@ -451,8 +451,8 @@ module TagsSubstitutionConcern
def tags_and_datas_list(dossier)
[
[champ_public_tags(dossier:), dossier.champs_public],
[champ_private_tags(dossier:), dossier.champs_private],
[champ_public_tags(dossier:), dossier],
[champ_private_tags(dossier:), dossier],
[dossier_tags, dossier],
[ROUTAGE_TAGS, dossier],
[INDIVIDUAL_TAGS, dossier.individual],

View file

@ -1047,14 +1047,8 @@ class Dossier < ApplicationRecord
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)
# nil => [nil]
# text => [text]
# [commune, insee, departement] => [commune, insee, departement]
wrapped_exported_values = [champ.for_export].flatten
wrapped_exported_values.map.with_index do |champ_value, index|
[type_de_champ.libelle_for_export(index), champ_value]
type_de_champ.libelles_for_export.map do |(libelle, path)|
[libelle, champ&.for_export(path)]
end
end
end
@ -1184,11 +1178,8 @@ class Dossier < ApplicationRecord
def champ_for_export(type_de_champ, row_id)
champ = champs_by_public_id[type_de_champ.public_id(row_id)]
if champ.nil? || !champ.visible?
# some champs export multiple columns
# ex: commune.for_export => [commune, insee, departement]
# so we build a fake champ to have the right export
type_de_champ.build_champ(dossier: self, row_id:)
if champ.blank? || !champ.visible?
nil
else
champ
end

View file

@ -145,7 +145,7 @@ class TypeDeChamp < ApplicationRecord
has_one :revision, through: :revision_type_de_champ
has_one :procedure, through: :revision
delegate :estimated_fill_duration, :estimated_read_duration, :tags_for_template, :libelle_for_export, :primary_options, :secondary_options, to: :dynamic_type
delegate :estimated_fill_duration, :estimated_read_duration, :tags_for_template, :libelles_for_export, :libelle_for_export, :primary_options, :secondary_options, to: :dynamic_type
delegate :used_by_routing_rules?, to: :revision_type_de_champ
class WithIndifferentAccess

View file

@ -1,21 +1,25 @@
class TypesDeChamp::AddressTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def tags_for_template
tags = super
stable_id = @type_de_champ.stable_id
tags.push(
def libelles_for_export
path = paths.first
[[path[:libelle], path[:path]]]
end
private
def paths
paths = super
paths.push(
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)} (Département)",
id: "tdc#{stable_id}/departement",
description: "#{description} (Département)",
lambda: -> (champs) { champs.find { _1.stable_id == stable_id }&.departement_code_and_name }
libelle: "#{libelle} (Département)",
path: :departement,
description: "#{description} (Département)"
},
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)} (Commune)",
id: "tdc#{stable_id}/commune",
description: "#{description} (Commune)",
lambda: -> (champs) { champs.find { _1.stable_id == stable_id }&.commune_name }
libelle: "#{libelle} (Commune)",
path: :commune,
description: "#{description} (Commune)"
}
)
tags
paths
end
end

View file

@ -1,19 +1,20 @@
class TypesDeChamp::CommuneTypeDeChamp < TypesDeChamp::TypeDeChampBase
def libelle_for_export(index)
[libelle, "#{libelle} (Code insee)", "#{libelle} (Département)"][index]
end
private
def tags_for_template
tags = super
stable_id = @type_de_champ.stable_id
tags.push(
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)} (Département)",
id: "tdc#{stable_id}/departement",
description: "#{description} (Département)",
lambda: -> (champs) { champs.find { _1.stable_id == stable_id }&.departement_code_and_name }
}
)
tags
def paths
paths = super
paths.push({
libelle: "#{libelle} (Code INSEE)",
description: "#{description} (Code INSEE)",
path: :code,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle} (Département)",
description: "#{description} (Département)",
path: :departement,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -1,9 +1,18 @@
class TypesDeChamp::DepartementTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def libelle_for_export(index)
[libelle, "#{libelle} (Code)"][index]
end
def filter_to_human(filter_value)
APIGeoService.departement_name(filter_value).presence || filter_value
end
private
def paths
paths = super
paths.push({
libelle: "#{libelle} (Code)",
description: "#{description} (Code)",
path: :code,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -1,5 +1,20 @@
class TypesDeChamp::EpciTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def libelle_for_export(index)
[libelle, "#{libelle} (Code)", "#{libelle} (Département)"][index]
private
def paths
paths = super
paths.push({
libelle: "#{libelle} (Code)",
description: "#{description} (Code)",
path: :code,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle} (Département)",
description: "#{description} (Département)",
path: :departement,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -4,30 +4,9 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
delegate :drop_down_list_options, to: :@type_de_champ
validate :check_presence_of_primary_options
def tags_for_template
tags = super
stable_id = @type_de_champ.stable_id
tags.push(
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)}/primaire",
id: "tdc#{stable_id}/primaire",
description: "#{description} (menu primaire)",
lambda: -> (champs) {
champs.find { |champ| champ.stable_id == stable_id }&.primary_value
}
}
)
tags.push(
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)}/secondaire",
id: "tdc#{stable_id}/secondaire",
description: "#{description} (menu secondaire)",
lambda: -> (champs) {
champs.find { |champ| champ.stable_id == stable_id }&.secondary_value
}
}
)
tags
def libelles_for_export
path = paths.first
[[path[:libelle], path[:path]]]
end
def add_blank_option_when_not_mandatory(options)
@ -53,6 +32,23 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
private
def paths
paths = super
paths.push({
libelle: "#{libelle}/primaire",
description: "#{description} (Primaire)",
path: :primary,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle}/secondaire",
description: "#{description} (Secondaire)",
path: :secondary,
maybe_null: public? && !mandatory?
})
paths
end
def unpack_options
_, *options = drop_down_list_options
chunked = options.slice_before(PRIMARY_PATTERN)

View file

@ -1,5 +1,14 @@
class TypesDeChamp::PaysTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def libelle_for_export(index)
[libelle, "#{libelle} (Code)"][index]
private
def paths
paths = super
paths.push({
libelle: "#{libelle} (Code)",
description: "#{description} (Code)",
path: :code,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -1,9 +1,18 @@
class TypesDeChamp::RegionTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def libelle_for_export(index)
[libelle, "#{libelle} (Code)"][index]
end
def filter_to_human(filter_value)
APIGeoService.region_name(filter_value).presence || filter_value
end
private
def paths
paths = super
paths.push({
libelle: "#{libelle} (Code)",
description: "#{description} (Code)",
path: :code,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -12,7 +12,7 @@ class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase
end
# We have to truncate the label here as spreadsheets have a (30 char) limit on length.
def libelle_for_export(index = 0)
def libelle_for_export
str = "(#{stable_id}) #{libelle}"
# /\*?[] are invalid Excel worksheet characters
ActiveStorage::Filename.new(str.delete('[]*?')).sanitized

View file

@ -1,25 +1,32 @@
class TypesDeChamp::RNFTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def libelle_for_export(index)
[libelle, "#{libelle} (Nom)", "#{libelle} (Adresse)", "#{libelle} (Code insee Ville)", "#{libelle} (Département)"][index]
end
private
def tags_for_template
tags = super
stable_id = @type_de_champ.stable_id
tags.push(
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)} (Département)",
id: "tdc#{stable_id}/departement",
description: "#{description} (Département)",
lambda: -> (champs) { champs.find { _1.stable_id == stable_id }&.departement_code_and_name }
},
{
libelle: "#{TagsSubstitutionConcern::TagsParser.normalize(libelle)} (Commune)",
id: "tdc#{stable_id}/commune",
description: "#{description} (Commune)",
lambda: -> (champs) { champs.find { _1.stable_id == stable_id }&.commune_name }
}
)
tags
def paths
paths = super
paths.push({
libelle: "#{libelle} (Nom)",
description: "#{description} (Nom)",
path: :nom,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle} (Adresse)",
description: "#{description} (Adresse)",
path: :address,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle} (Code INSEE Ville)",
description: "#{description} (Code INSEE Ville)",
path: :code_insee,
maybe_null: public? && !mandatory?
})
paths.push({
libelle: "#{libelle} (Département)",
description: "#{description} (Département)",
path: :departement,
maybe_null: public? && !mandatory?
})
paths
end
end

View file

@ -13,22 +13,18 @@ class TypesDeChamp::TypeDeChampBase
end
def tags_for_template
stable_id = self.stable_id
[
{
libelle: TagsSubstitutionConcern::TagsParser.normalize(libelle),
id: "tdc#{stable_id}",
description: description,
maybe_null: public? && !mandatory?,
lambda: -> (champs) {
champs.find { |champ| champ.stable_id == stable_id }&.for_tag
}
}
]
tdc = @type_de_champ
paths.map do |path|
path.merge(
libelle: TagsSubstitutionConcern::TagsParser.normalize(path[:libelle]),
id: path[:path] == :value ? "tdc#{stable_id}" : "tdc#{stable_id}/#{path[:path]}",
lambda: -> (dossier) { dossier.project_champ(tdc, nil).for_tag(path[:path]) }
)
end
end
def libelle_for_export(index = 0)
libelle
def libelles_for_export
paths.map { [_1[:libelle], _1[:path]] }
end
# Default estimated duration to fill the champ in a form, in seconds.
@ -59,4 +55,17 @@ class TypesDeChamp::TypeDeChampBase
def human_to_filter(human_value)
human_value
end
private
def paths
[
{
libelle:,
path: :value,
description:,
maybe_null: public? && !mandatory?
}
]
end
end