Merge pull request #10958 from tchak/refactor-champ-value

refactor(champ): move champ value format methods from TypeDeChamp class to instance
This commit is contained in:
Paul Chavard 2024-10-21 11:55:17 +00:00 committed by GitHub
commit 0e95381002
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 484 additions and 537 deletions

View file

@ -7,10 +7,14 @@ module Types
global_id_field :id global_id_field :id
field :champ_descriptor_id, String, "L'identifiant du champDescriptor de ce champ", null: false field :champ_descriptor_id, String, "L'identifiant du champDescriptor de ce champ", null: false
field :label, String, "Libellé du champ.", null: false, method: :libelle field :label, String, "Libellé du champ.", null: false, method: :libelle
field :string_value, String, "La valeur du champ sous forme texte.", null: true, method: :for_api_v2 field :string_value, String, "La valeur du champ sous forme texte.", null: true
field :updated_at, GraphQL::Types::ISO8601DateTime, "Date de dernière modification du champ.", null: false field :updated_at, GraphQL::Types::ISO8601DateTime, "Date de dernière modification du champ.", null: false
field :prefilled, Boolean, null: false, method: :prefilled? field :prefilled, Boolean, null: false, method: :prefilled?
def string_value
object.type_de_champ.champ_value_for_api(object)
end
definition_methods do definition_methods do
def resolve_type(object, context) def resolve_type(object, context)
case object case object

View file

@ -111,23 +111,11 @@ class Champ < ApplicationRecord
end end
def to_s def to_s
TypeDeChamp.champ_value(type_champ, self) type_de_champ.champ_value(self)
end end
def for_api def last_write_type_champ
TypeDeChamp.champ_value_for_api(type_champ, self, 1) TypeDeChamp::CHAMP_TYPE_TO_TYPE_CHAMP.fetch(type)
end
def for_api_v2
TypeDeChamp.champ_value_for_api(type_champ, self, 2)
end
def for_export(path = :value)
TypeDeChamp.champ_value_for_export(type_champ, self, path)
end
def for_tag(path = :value)
TypeDeChamp.champ_value_for_tag(type_champ, self, path)
end end
def main_value_name def main_value_name

View file

@ -4,14 +4,6 @@ class Champs::IbanChamp < Champ
validates_with IbanValidator, if: :validate_champ_value_or_prefill? validates_with IbanValidator, if: :validate_champ_value_or_prefill?
after_validation :format_iban after_validation :format_iban
def for_api
to_s.gsub(/\s+/, '')
end
def for_api_v2
for_api
end
private private
def format_iban def format_iban

View file

@ -81,13 +81,18 @@ module DossierChampsConcern
def champs_for_export(types_de_champ, row_id = nil) def champs_for_export(types_de_champ, row_id = nil)
types_de_champ.flat_map do |type_de_champ| types_de_champ.flat_map do |type_de_champ|
champ = champ_for_export(type_de_champ, row_id) champ = filled_champ(type_de_champ, row_id)
type_de_champ.libelles_for_export.map do |(libelle, path)| type_de_champ.libelles_for_export.map do |(libelle, path)|
[libelle, TypeDeChamp.champ_value_for_export(type_de_champ.type_champ, champ, path)] [libelle, type_de_champ.champ_value_for_export(champ, path)]
end end
end end
end end
def champ_value_for_tag(type_de_champ, path = :value)
champ = filled_champ(type_de_champ, nil)
type_de_champ.champ_value_for_tag(champ, path)
end
def champ_for_update(type_de_champ, row_id, updated_by:) def champ_for_update(type_de_champ, row_id, updated_by:)
champ, attributes = champ_with_attributes_for_update(type_de_champ, row_id, updated_by:) champ, attributes = champ_with_attributes_for_update(type_de_champ, row_id, updated_by:)
champ.assign_attributes(attributes) champ.assign_attributes(attributes)
@ -143,7 +148,7 @@ module DossierChampsConcern
@champs_by_public_id ||= champs.sort_by(&:id).index_by(&:public_id) @champs_by_public_id ||= champs.sort_by(&:id).index_by(&:public_id)
end end
def champ_for_export(type_de_champ, row_id) def filled_champ(type_de_champ, row_id)
champ = champs_by_public_id[type_de_champ.public_id(row_id)] champ = champs_by_public_id[type_de_champ.public_id(row_id)]
if champ.blank? || !champ.visible? if champ.blank? || !champ.visible?
nil nil

View file

@ -50,7 +50,8 @@ class Logic::ChampValue < Logic::Term
"Champs::CheckboxChamp" "Champs::CheckboxChamp"
targeted_champ.true? targeted_champ.true?
when "Champs::IntegerNumberChamp", "Champs::DecimalNumberChamp" when "Champs::IntegerNumberChamp", "Champs::DecimalNumberChamp"
targeted_champ.for_api # TODO expose raw typed value of champs
targeted_champ.type_de_champ.champ_value_for_api(targeted_champ, version: 1)
when "Champs::DropDownListChamp" when "Champs::DropDownListChamp"
targeted_champ.selected targeted_champ.selected
when "Champs::MultipleDropDownListChamp" when "Champs::MultipleDropDownListChamp"

View file

@ -696,43 +696,43 @@ class TypeDeChamp < ApplicationRecord
options.slice(*kept_keys.map(&:to_s)) options.slice(*kept_keys.map(&:to_s))
end end
class << self def champ_value(champ)
def champ_value(type_champ, champ) if use_default_value?(champ)
dynamic_type_class = type_champ_to_class_name(type_champ).constantize dynamic_type.champ_default_value
if use_default_value?(type_champ, champ)
dynamic_type_class.champ_default_value
else else
dynamic_type_class.champ_value(champ) dynamic_type.champ_value(champ)
end end
end end
def champ_value_for_api(type_champ, champ, version = 2) def champ_value_for_api(champ, version: 2)
dynamic_type_class = type_champ_to_class_name(type_champ).constantize if use_default_value?(champ)
if use_default_value?(type_champ, champ) dynamic_type.champ_default_api_value(version)
dynamic_type_class.champ_default_api_value(version)
else else
dynamic_type_class.champ_value_for_api(champ, version) dynamic_type.champ_value_for_api(champ, version:)
end end
end end
def champ_value_for_export(type_champ, champ, path = :value) def champ_value_for_export(champ, path = :value)
dynamic_type_class = type_champ_to_class_name(type_champ).constantize if use_default_value?(champ)
if use_default_value?(type_champ, champ) dynamic_type.champ_default_export_value(path)
dynamic_type_class.champ_default_export_value(path)
else else
dynamic_type_class.champ_value_for_export(champ, path) dynamic_type.champ_value_for_export(champ, path)
end end
end end
def champ_value_for_tag(type_champ, champ, path = :value) def champ_value_for_tag(champ, path = :value)
if use_default_value?(type_champ, champ) if use_default_value?(champ)
'' ''
else else
dynamic_type_class = type_champ_to_class_name(type_champ).constantize dynamic_type.champ_value_for_tag(champ, path)
dynamic_type_class.champ_value_for_tag(champ, path)
end end
end end
def html_id(row_id = nil)
"champ-#{public_id(row_id)}"
end
class << self
def type_champ_to_champ_class_name(type_champ) def type_champ_to_champ_class_name(type_champ)
"Champs::#{type_champ.classify}Champ" "Champs::#{type_champ.classify}Champ"
end end
@ -740,15 +740,18 @@ class TypeDeChamp < ApplicationRecord
def type_champ_to_class_name(type_champ) def type_champ_to_class_name(type_champ)
"TypesDeChamp::#{type_champ.classify}TypeDeChamp" "TypesDeChamp::#{type_champ.classify}TypeDeChamp"
end end
end
CHAMP_TYPE_TO_TYPE_CHAMP = type_champs.values.map { [type_champ_to_champ_class_name(_1), _1] }.to_h
private private
def use_default_value?(type_champ, champ) def use_default_value?(champ)
# no champ # no champ
return true if champ.nil? return true if champ.nil?
# type de champ on the revision changed # type de champ on the revision changed
if type_champ != champ.type_champ if champ.last_write_type_champ != type_champ
return !castable_on_change?(type_champ, champ.type_champ) return !castable_on_change?(champ.last_write_type_champ, type_champ)
end end
# special case for linked drop down champ it's blank implementation is not what you think # special case for linked drop down champ it's blank implementation is not what you think
return champ.value.blank? if type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list) return champ.value.blank? if type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
@ -768,13 +771,6 @@ class TypeDeChamp < ApplicationRecord
false false
end end
end end
end
def html_id(row_id = nil)
"champ-#{public_id(row_id)}"
end
private
def populate_stable_id def populate_stable_id
if !stable_id if !stable_id

View file

@ -6,12 +6,11 @@ class TypesDeChamp::AddressTypeDeChamp < TypesDeChamp::TextTypeDeChamp
[[path[:libelle], path[:path]]] [[path[:libelle], path[:path]]]
end end
class << self
def champ_value(champ) def champ_value(champ)
champ.address_label.presence || '' champ.address_label.presence || ''
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
champ_value(champ) champ_value(champ)
end end
@ -36,7 +35,6 @@ class TypesDeChamp::AddressTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ.commune_name champ.commune_name
end end
end end
end
private private

View file

@ -20,8 +20,7 @@ class TypesDeChamp::CarteTypeDeChamp < TypesDeChamp::TypeDeChampBase
def tags_for_template = [].freeze def tags_for_template = [].freeze
class << self def champ_value_for_api(champ, version: 2)
def champ_value_for_api(champ, version = 2)
nil nil
end end
@ -29,4 +28,3 @@ class TypesDeChamp::CarteTypeDeChamp < TypesDeChamp::TypeDeChampBase
champ.geo_areas.map(&:label).join("\n") champ.geo_areas.map(&:label).join("\n")
end end
end end
end

View file

@ -11,7 +11,6 @@ class TypesDeChamp::CheckboxTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end
end end
class << self
def champ_value(champ) def champ_value(champ)
champ.true? ? 'Oui' : 'Non' champ.true? ? 'Oui' : 'Non'
end end
@ -24,7 +23,7 @@ class TypesDeChamp::CheckboxTypeDeChamp < TypesDeChamp::TypeDeChampBase
champ.true? ? 'on' : 'off' champ.true? ? 'on' : 'off'
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 2 when 2
champ.true? ? 'true' : 'false' champ.true? ? 'true' : 'false'
@ -50,4 +49,3 @@ class TypesDeChamp::CheckboxTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end
end end
end end
end

View file

@ -1,9 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::COJOTypeDeChamp < TypesDeChamp::TextTypeDeChamp class TypesDeChamp::COJOTypeDeChamp < TypesDeChamp::TextTypeDeChamp
class << self
def champ_value(champ) def champ_value(champ)
"#{champ.accreditation_number} #{champ.accreditation_birthdate}" "#{champ.accreditation_number} #{champ.accreditation_birthdate}"
end end
end end
end

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::CommuneTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::CommuneTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
case path case path
when :value when :value
@ -27,7 +26,6 @@ class TypesDeChamp::CommuneTypeDeChamp < TypesDeChamp::TypeDeChampBase
def champ_value(champ) def champ_value(champ)
champ.code_postal? ? "#{champ.name} (#{champ.code_postal})" : champ.name champ.code_postal? ? "#{champ.name} (#{champ.code_postal})" : champ.name
end end
end
private private

View file

@ -1,11 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::DateTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::DateTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value(champ) def champ_value(champ)
I18n.l(Time.zone.parse(champ.value), format: '%d %B %Y') I18n.l(Time.zone.parse(champ.value), format: '%d %B %Y')
rescue ArgumentError rescue ArgumentError
champ.value.presence || "" # old dossiers can have not parseable dates champ.value.presence || "" # old dossiers can have not parseable dates
end end
end end
end

View file

@ -1,9 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::DatetimeTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::DatetimeTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value(champ) def champ_value(champ)
I18n.l(Time.zone.parse(champ.value)) I18n.l(Time.zone.parse(champ.value))
end end
end end
end

View file

@ -1,12 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::DecimalNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::DecimalNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
champ_formatted_value(champ) champ_formatted_value(champ)
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 1 when 1
champ_formatted_value(champ) champ_formatted_value(champ)
@ -25,4 +24,3 @@ class TypesDeChamp::DecimalNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
champ.value&.to_f champ.value&.to_f
end end
end end
end

View file

@ -5,7 +5,6 @@ class TypesDeChamp::DepartementTypeDeChamp < TypesDeChamp::TextTypeDeChamp
APIGeoService.departement_name(filter_value).presence || filter_value APIGeoService.departement_name(filter_value).presence || filter_value
end end
class << self
def champ_value(champ) def champ_value(champ)
"#{champ.code} #{champ.name}" "#{champ.code} #{champ.name}"
end end
@ -28,7 +27,7 @@ class TypesDeChamp::DepartementTypeDeChamp < TypesDeChamp::TextTypeDeChamp
end end
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 2 when 2
champ_value(champ).tr('', '-') champ_value(champ).tr('', '-')
@ -36,7 +35,6 @@ class TypesDeChamp::DepartementTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ_value(champ) champ_value(champ)
end end
end end
end
private private

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::EpciTypeDeChamp < TypesDeChamp::TextTypeDeChamp class TypesDeChamp::EpciTypeDeChamp < TypesDeChamp::TextTypeDeChamp
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
case path case path
when :value when :value
@ -23,7 +22,6 @@ class TypesDeChamp::EpciTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ.departement_code_and_name champ.departement_code_and_name
end end
end end
end
private private

View file

@ -4,4 +4,8 @@ class TypesDeChamp::IbanTypeDeChamp < TypesDeChamp::TypeDeChampBase
def estimated_fill_duration(revision) def estimated_fill_duration(revision)
FILL_DURATION_MEDIUM FILL_DURATION_MEDIUM
end end
def champ_value_for_api(champ, version: 2)
champ_value(champ).gsub(/\s+/, '')
end
end end

View file

@ -1,12 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::IntegerNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::IntegerNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
champ_formatted_value(champ) champ_formatted_value(champ)
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 1 when 1
champ_formatted_value(champ) champ_formatted_value(champ)
@ -25,4 +24,3 @@ class TypesDeChamp::IntegerNumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
champ.value&.to_i champ.value&.to_i
end end
end end
end

View file

@ -32,7 +32,6 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
secondary_options secondary_options
end end
class << self
def champ_value(champ) def champ_value(champ)
[champ.primary_value, champ.secondary_value].filter(&:present?).join(' / ') [champ.primary_value, champ.secondary_value].filter(&:present?).join(' / ')
end end
@ -59,7 +58,7 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
end end
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 1 when 1
{ primary: champ.primary_value, secondary: champ.secondary_value } { primary: champ.primary_value, secondary: champ.secondary_value }
@ -67,7 +66,6 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
super super
end end
end end
end
private private

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
class << self
def champ_value(champ) def champ_value(champ)
champ.selected_options.join(', ') champ.selected_options.join(', ')
end end
@ -14,4 +13,3 @@ class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampB
champ.selected_options.join(', ') champ.selected_options.join(', ')
end end
end end
end

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::PaysTypeDeChamp < TypesDeChamp::TextTypeDeChamp class TypesDeChamp::PaysTypeDeChamp < TypesDeChamp::TextTypeDeChamp
class << self
def champ_value(champ) def champ_value(champ)
champ.name champ.name
end end
@ -23,7 +22,6 @@ class TypesDeChamp::PaysTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ.code champ.code
end end
end end
end
private private

View file

@ -22,7 +22,6 @@ class TypesDeChamp::PhoneTypeDeChamp < TypesDeChamp::TextTypeDeChamp
# See issue #6996. # See issue #6996.
DEFAULT_COUNTRY_CODES = [:FR, :GP, :GF, :MQ, :RE, :YT, :NC, :PF].freeze DEFAULT_COUNTRY_CODES = [:FR, :GP, :GF, :MQ, :RE, :YT, :NC, :PF].freeze
class << self
def champ_value(champ) def champ_value(champ)
if Phonelib.valid_for_countries?(champ.value, DEFAULT_COUNTRY_CODES) if Phonelib.valid_for_countries?(champ.value, DEFAULT_COUNTRY_CODES)
Phonelib.parse_for_countries(champ.value, DEFAULT_COUNTRY_CODES).full_national Phonelib.parse_for_countries(champ.value, DEFAULT_COUNTRY_CODES).full_national
@ -33,4 +32,3 @@ class TypesDeChamp::PhoneTypeDeChamp < TypesDeChamp::TextTypeDeChamp
end end
end end
end end
end

View file

@ -7,12 +7,11 @@ class TypesDeChamp::PieceJustificativeTypeDeChamp < TypesDeChamp::TypeDeChampBas
def tags_for_template = [].freeze def tags_for_template = [].freeze
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
champ.piece_justificative_file.map { _1.filename.to_s }.join(', ') champ.piece_justificative_file.map { _1.filename.to_s }.join(', ')
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
return if version == 2 return if version == 2
# API v1 don't support multiple PJ # API v1 don't support multiple PJ
@ -24,4 +23,3 @@ class TypesDeChamp::PieceJustificativeTypeDeChamp < TypesDeChamp::TypeDeChampBas
end end
end end
end end
end

View file

@ -5,7 +5,6 @@ class TypesDeChamp::RegionTypeDeChamp < TypesDeChamp::TextTypeDeChamp
APIGeoService.region_name(filter_value).presence || filter_value APIGeoService.region_name(filter_value).presence || filter_value
end end
class << self
def champ_value(champ) def champ_value(champ)
champ.name champ.name
end end
@ -27,7 +26,6 @@ class TypesDeChamp::RegionTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ.code champ.code
end end
end end
end
private private

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase
def self.champ_value_for_tag(champ, path = :value) def champ_value_for_tag(champ, path = :value)
return nil if path != :value return nil if path != :value
return champ_default_value if champ.rows.blank? return champ_default_value if champ.rows.blank?

View file

@ -7,9 +7,7 @@ class TypesDeChamp::RNATypeDeChamp < TypesDeChamp::TypeDeChampBase
FILL_DURATION_MEDIUM FILL_DURATION_MEDIUM
end end
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
champ.identifier champ.identifier
end end
end end
end

View file

@ -3,7 +3,6 @@
class TypesDeChamp::RNFTypeDeChamp < TypesDeChamp::TextTypeDeChamp class TypesDeChamp::RNFTypeDeChamp < TypesDeChamp::TextTypeDeChamp
include AddressableColumnConcern include AddressableColumnConcern
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
case path case path
when :value when :value
@ -33,7 +32,6 @@ class TypesDeChamp::RNFTypeDeChamp < TypesDeChamp::TextTypeDeChamp
champ.title || '' champ.title || ''
end end
end end
end
private private

View file

@ -5,9 +5,7 @@ class TypesDeChamp::TextareaTypeDeChamp < TypesDeChamp::TextTypeDeChamp
FILL_DURATION_MEDIUM FILL_DURATION_MEDIUM
end end
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
ActionView::Base.full_sanitizer.sanitize(champ.value) ActionView::Base.full_sanitizer.sanitize(champ.value)
end end
end end
end

View file

@ -10,12 +10,11 @@ class TypesDeChamp::TitreIdentiteTypeDeChamp < TypesDeChamp::TypeDeChampBase
def tags_for_template = [].freeze def tags_for_template = [].freeze
class << self
def champ_value_for_export(champ, path = :value) def champ_value_for_export(champ, path = :value)
champ.piece_justificative_file.attached? ? "présent" : "absent" champ.piece_justificative_file.attached? ? "présent" : "absent"
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
nil nil
end end
@ -23,4 +22,3 @@ class TypesDeChamp::TitreIdentiteTypeDeChamp < TypesDeChamp::TypeDeChampBase
"absent" "absent"
end end
end end
end

View file

@ -15,12 +15,12 @@ class TypesDeChamp::TypeDeChampBase
end end
def tags_for_template def tags_for_template
tdc = @type_de_champ type_de_champ = @type_de_champ
paths.map do |path| paths.map do |path|
path.merge( path.merge(
libelle: TagsSubstitutionConcern::TagsParser.normalize(path[:libelle]), libelle: TagsSubstitutionConcern::TagsParser.normalize(path[:libelle]),
id: path[:path] == :value ? "tdc#{stable_id}" : "tdc#{stable_id}/#{path[:path]}", id: path[:path] == :value ? "tdc#{stable_id}" : "tdc#{stable_id}/#{path[:path]}",
lambda: -> (dossier) { dossier.project_champ(tdc, nil).for_tag(path[:path]) } lambda: -> (dossier) { dossier.champ_value_for_tag(type_de_champ, path[:path]) }
) )
end end
end end
@ -54,12 +54,11 @@ class TypesDeChamp::TypeDeChampBase
filter_value filter_value
end end
class << self
def champ_value(champ) def champ_value(champ)
champ.value.present? ? champ.value.to_s : champ_default_value champ.value.present? ? champ.value.to_s : champ_default_value
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 2 when 2
champ_value(champ) champ_value(champ)
@ -92,7 +91,6 @@ class TypesDeChamp::TypeDeChampBase
nil nil
end end
end end
end
def columns(procedure_id:, displayable: true, prefix: nil) def columns(procedure_id:, displayable: true, prefix: nil)
[ [

View file

@ -11,7 +11,6 @@ class TypesDeChamp::YesNoTypeDeChamp < TypesDeChamp::CheckboxTypeDeChamp
end end
end end
class << self
def champ_value(champ) def champ_value(champ)
champ_formatted_value(champ) champ_formatted_value(champ)
end end
@ -24,7 +23,7 @@ class TypesDeChamp::YesNoTypeDeChamp < TypesDeChamp::CheckboxTypeDeChamp
champ_formatted_value(champ) champ_formatted_value(champ)
end end
def champ_value_for_api(champ, version = 2) def champ_value_for_api(champ, version: 2)
case version case version
when 2 when 2
champ.true? ? 'true' : 'false' champ.true? ? 'true' : 'false'
@ -56,4 +55,3 @@ class TypesDeChamp::YesNoTypeDeChamp < TypesDeChamp::CheckboxTypeDeChamp
champ.true? ? 'Oui' : 'Non' champ.true? ? 'Oui' : 'Non'
end end
end end
end

View file

@ -17,7 +17,7 @@ class ChampSerializer < ActiveModel::Serializer
when GeoArea when GeoArea
object.geometry object.geometry
else else
object.for_api object.type_de_champ.champ_value_for_api(object, version: 1)
end end
end end

View file

@ -65,7 +65,7 @@ class DossierSerializer < ActiveModel::Serializer
{ {
created_at: champ.created_at&.in_time_zone('UTC'), created_at: champ.created_at&.in_time_zone('UTC'),
type_de_piece_justificative_id: champ.type_de_champ.old_pj[:stable_id], type_de_piece_justificative_id: champ.type_de_champ.old_pj[:stable_id],
content_url: champ.for_api, content_url: champ.type_de_champ.champ_value_for_api(champ, version: 1),
user: champ.dossier.user user: champ.dossier.user
} }
end.flatten end.flatten

View file

@ -175,16 +175,16 @@ class DossierProjectionService
def champ_value_formatter(dossiers_ids, fields) def champ_value_formatter(dossiers_ids, fields)
stable_ids = fields.filter { _1[TABLE].in?(['type_de_champ', 'type_de_champ_private']) }.map { _1[COLUMN] } stable_ids = fields.filter { _1[TABLE].in?(['type_de_champ', 'type_de_champ_private']) }.map { _1[COLUMN] }
revision_ids_by_dossier_ids = Dossier.where(id: dossiers_ids).pluck(:id, :revision_id).to_h revision_ids_by_dossier_ids = Dossier.where(id: dossiers_ids).pluck(:id, :revision_id).to_h
stable_ids_and_types_champ_by_revision_ids = ProcedureRevisionTypeDeChamp.includes(:type_de_champ) stable_ids_and_types_de_champ_by_revision_ids = ProcedureRevisionTypeDeChamp.includes(:type_de_champ)
.where(revision_id: revision_ids_by_dossier_ids.values.uniq, type_de_champ: { stable_id: stable_ids }) .where(revision_id: revision_ids_by_dossier_ids.values.uniq, type_de_champ: { stable_id: stable_ids })
.pluck(:revision_id, 'type_de_champ.stable_id', 'type_de_champ.type_champ') .map { [_1.revision_id, _1.type_de_champ] }
.group_by(&:first) .group_by(&:first)
.transform_values { _1.map { |_, stable_id, type_champ| [stable_id, type_champ] }.to_h } .transform_values { _1.map { |_, type_de_champ| [type_de_champ.stable_id, type_de_champ] }.to_h }
stable_ids_and_types_champ_by_dossier_ids = revision_ids_by_dossier_ids.transform_values { stable_ids_and_types_champ_by_revision_ids[_1] }.compact stable_ids_and_types_de_champ_by_dossier_ids = revision_ids_by_dossier_ids.transform_values { stable_ids_and_types_de_champ_by_revision_ids[_1] }.compact
-> (champ) { -> (champ) {
type_champ = stable_ids_and_types_champ_by_dossier_ids.fetch(champ.dossier_id, {})[champ.stable_id] type_de_champ = stable_ids_and_types_de_champ_by_dossier_ids.fetch(champ.dossier_id, {})[champ.stable_id]
if type_champ.present? && TypeDeChamp.type_champ_to_champ_class_name(type_champ) == champ.type if type_de_champ.present? && type_de_champ.type_champ == champ.last_write_type_champ
TypeDeChamp.champ_value(type_champ, champ) type_de_champ.champ_value(champ)
else else
'' ''
end end

View file

@ -519,7 +519,7 @@ describe API::V2::GraphqlController do
{ {
id: champ.to_typed_id, id: champ.to_typed_id,
label: champ.libelle, label: champ.libelle,
stringValue: champ.for_api_v2 stringValue: champ.type_de_champ.champ_value_for_api(champ)
} }
end end
expect(gql_data[:dossier][:champs]).to match_array(expected_champs) expect(gql_data[:dossier][:champs]).to match_array(expected_champs)

View file

@ -176,10 +176,12 @@ describe Champ do
let(:champ) { Champs::TextChamp.new(value:, dossier: build(:dossier)) } let(:champ) { Champs::TextChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) } before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) }
let(:value_for_export) { champ.type_de_champ.champ_value_for_export(champ) }
context 'when type_de_champ is text' do context 'when type_de_champ is text' do
let(:value) { '123' } let(:value) { '123' }
it { expect(champ.for_export).to eq('123') } it { expect(value_for_export).to eq('123') }
end end
context 'when type_de_champ is textarea' do context 'when type_de_champ is textarea' do
@ -188,7 +190,7 @@ describe Champ do
let(:value) { '<b>gras<b>' } let(:value) { '<b>gras<b>' }
it { expect(champ.for_export).to eq('gras') } it { expect(value_for_export).to eq('gras') }
end end
context 'when type_de_champ is yes_no' do context 'when type_de_champ is yes_no' do
@ -198,19 +200,19 @@ describe Champ do
context 'if yes' do context 'if yes' do
let(:value) { 'true' } let(:value) { 'true' }
it { expect(champ.for_export).to eq('Oui') } it { expect(value_for_export).to eq('Oui') }
end end
context 'if no' do context 'if no' do
let(:value) { 'false' } let(:value) { 'false' }
it { expect(champ.for_export).to eq('Non') } it { expect(value_for_export).to eq('Non') }
end end
context 'if nil' do context 'if nil' do
let(:value) { nil } let(:value) { nil }
it { expect(champ.for_export).to eq('Non') } it { expect(value_for_export).to eq('Non') }
end end
end end
@ -220,19 +222,21 @@ describe Champ do
let(:value) { '["Crétinier", "Mousserie"]' } let(:value) { '["Crétinier", "Mousserie"]' }
it { expect(champ.for_export).to eq('Crétinier, Mousserie') } it { expect(value_for_export).to eq('Crétinier, Mousserie') }
end end
context 'when type_de_champ and champ.type mismatch' do context 'when type_de_champ and champ.type mismatch' do
let(:value) { :noop } let(:value) { :noop }
let(:champ_yes_no) { Champs::YesNoChamp.new(value: 'true') } let(:champ_yes_no) { Champs::YesNoChamp.new(value: 'true') }
let(:champ_text) { Champs::TextChamp.new(value: 'hello') } let(:champ_text) { Champs::TextChamp.new(value: 'hello') }
let(:type_de_champ_yes_no) { build(:type_de_champ_yes_no) }
let(:type_de_champ_text) { build(:type_de_champ_text) }
before do before do
allow(champ_yes_no).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) allow(champ_yes_no).to receive(:type_de_champ).and_return(type_de_champ_yes_no)
allow(champ_text).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) allow(champ_text).to receive(:type_de_champ).and_return(type_de_champ_text)
end end
it { expect(TypeDeChamp.champ_value_for_export('text', champ_yes_no)).to eq(nil) } it { expect(type_de_champ_text.champ_value_for_export(champ_yes_no)).to eq(nil) }
it { expect(TypeDeChamp.champ_value_for_export('yes_no', champ_text)).to eq('Non') } it { expect(type_de_champ_yes_no.champ_value_for_export(champ_text)).to eq('Non') }
end end
end end

View file

@ -50,7 +50,7 @@ describe Champs::CarteChamp do
let(:geo_areas) { [build(:geo_area, :selection_utilisateur, :point)] } let(:geo_areas) { [build(:geo_area, :selection_utilisateur, :point)] }
it "returns point label" do it "returns point label" do
expect(champ.for_export).to eq("Un point situé à 46°32'19\"N 2°25'42\"E") expect(champ.type_de_champ.champ_value_for_export(champ)).to eq("Un point situé à 46°32'19\"N 2°25'42\"E")
end end
end end
@ -58,7 +58,7 @@ describe Champs::CarteChamp do
let(:geo_areas) { [build(:geo_area, :selection_utilisateur, :cadastre)] } let(:geo_areas) { [build(:geo_area, :selection_utilisateur, :cadastre)] }
it "returns cadastre parcelle label" do it "returns cadastre parcelle label" do
expect(champ.for_export).to match(/Parcelle n° 42/) expect(champ.type_de_champ.champ_value_for_export(champ)).to match(/Parcelle n° 42/)
end end
end end
end end

View file

@ -23,9 +23,9 @@ describe Champs::CommuneChamp do
expect(champ.code).to eq(code_insee) expect(champ.code).to eq(code_insee)
expect(champ.code_departement).to eq(code_departement) expect(champ.code_departement).to eq(code_departement)
expect(champ.code_postal).to eq(code_postal) expect(champ.code_postal).to eq(code_postal)
expect(champ.for_export(:value)).to eq 'Châteldon (63290)' expect(champ.type_de_champ.champ_value_for_export(champ, :value)).to eq 'Châteldon (63290)'
expect(champ.for_export(:code)).to eq '63102' expect(champ.type_de_champ.champ_value_for_export(champ, :code)).to eq '63102'
expect(champ.for_export(:departement)).to eq '63 Puy-de-Dôme' expect(champ.type_de_champ.champ_value_for_export(champ, :departement)).to eq '63 Puy-de-Dôme'
end end
context 'with tricky bug (should not happen, but it happens)' do context 'with tricky bug (should not happen, but it happens)' do
@ -59,9 +59,9 @@ describe Champs::CommuneChamp do
expect(champ.code).to eq(code_insee) expect(champ.code).to eq(code_insee)
expect(champ.code_departement).to eq(code_departement) expect(champ.code_departement).to eq(code_departement)
expect(champ.code_postal).to eq(code_postal) expect(champ.code_postal).to eq(code_postal)
expect(champ.for_export(:value)).to eq 'Châteldon (63290)' expect(champ.type_de_champ.champ_value_for_export(champ, :value)).to eq 'Châteldon (63290)'
expect(champ.for_export(:code)).to eq '63102' expect(champ.type_de_champ.champ_value_for_export(champ, :code)).to eq '63102'
expect(champ.for_export(:departement)).to eq '63 Puy-de-Dôme' expect(champ.type_de_champ.champ_value_for_export(champ, :departement)).to eq '63 Puy-de-Dôme'
end end
end end
end end

View file

@ -69,7 +69,7 @@ describe Champs::DecimalNumberChamp do
describe 'for_export' do describe 'for_export' do
let(:champ) { Champs::DecimalNumberChamp.new(value:) } let(:champ) { Champs::DecimalNumberChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number)) } before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number)) }
subject { champ.for_export } subject { champ.type_de_champ.champ_value_for_export(champ) }
context 'with nil' do context 'with nil' do
let(:value) { 0 } let(:value) { 0 }
it { is_expected.to eq(0.0) } it { is_expected.to eq(0.0) }

View file

@ -80,7 +80,6 @@ describe Champs::DepartementChamp, type: :model do
expect(champ.value).to eq('Ain') expect(champ.value).to eq('Ain')
expect(champ.selected).to eq('01') expect(champ.selected).to eq('01')
expect(champ.to_s).to eq('01 Ain') expect(champ.to_s).to eq('01 Ain')
expect(champ.for_api_v2).to eq('01 - Ain')
end end
it 'with code having 3 chars' do it 'with code having 3 chars' do

View file

@ -55,7 +55,7 @@ describe Champs::LinkedDropDownListChamp do
let(:secondary_value) { nil } let(:secondary_value) { nil }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) } before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) }
subject { champ.for_export } subject { champ.type_de_champ.champ_value_for_export(champ) }
context 'with no value' do context 'with no value' do
let(:value) { nil } let(:value) { nil }

View file

@ -90,6 +90,6 @@ describe Champs::MultipleDropDownListChamp do
describe "#for_tag" do describe "#for_tag" do
let(:value) { ["val1", "val2"] } let(:value) { ["val1", "val2"] }
it { expect(champ.for_tag.to_s).to eq("val1, val2") } it { expect(champ.type_de_champ.champ_value_for_tag(champ).to_s).to eq("val1, val2") }
end end
end end

View file

@ -33,7 +33,7 @@ describe Champs::PieceJustificativeChamp do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first } let(:champ) { dossier.champs.first }
subject { champ.for_export } subject { champ.type_de_champ.champ_value_for_export(champ) }
it { is_expected.to eq('toto.txt') } it { is_expected.to eq('toto.txt') }
@ -50,7 +50,7 @@ describe Champs::PieceJustificativeChamp do
before { champ.piece_justificative_file.first.blob.update(virus_scan_result:) } before { champ.piece_justificative_file.first.blob.update(virus_scan_result:) }
subject { champ.for_api } subject { champ.type_de_champ.champ_value_for_api(champ, version: 1) }
context 'when file is safe' do context 'when file is safe' do
let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE } let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE }

View file

@ -19,7 +19,7 @@ describe Champs::RepetitionChamp do
end end
it "can render as string" do it "can render as string" do
expect(champ.for_tag.to_s).to eq( expect(champ.type_de_champ.champ_value_for_tag(champ).to_s).to eq(
<<~TXT.strip <<~TXT.strip
Languages Languages
@ -29,7 +29,7 @@ describe Champs::RepetitionChamp do
end end
it "as tiptap node" do it "as tiptap node" do
expect(champ.for_tag.to_tiptap_node).to include(type: 'orderedList') expect(champ.type_de_champ.champ_value_for_tag(champ).to_tiptap_node).to include(type: 'orderedList')
end end
end end
end end

View file

@ -23,11 +23,11 @@ describe Champs::RNAChamp do
champ.update(data: { association_titre: "Super asso" }) champ.update(data: { association_titre: "Super asso" })
end end
it { expect(champ.for_export).to eq("W182736273 (Super asso)") } it { expect(champ.type_de_champ.champ_value_for_export(champ)).to eq("W182736273 (Super asso)") }
end end
context "no association title" do context "no association title" do
it { expect(champ.for_export).to eq("W182736273") } it { expect(champ.type_de_champ.champ_value_for_export(champ)).to eq("W182736273") }
end end
end end
end end

View file

@ -125,11 +125,11 @@ describe Champs::RNFChamp, type: :model do
let(:champ) { described_class.new(external_id:, data: JSON.parse(body)) } let(:champ) { described_class.new(external_id:, data: JSON.parse(body)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rnf)) } before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rnf)) }
it do it do
expect(champ.for_export(:value)).to eq '075-FDD-00003-01' expect(champ.type_de_champ.champ_value_for_export(champ, :value)).to eq '075-FDD-00003-01'
expect(champ.for_export(:nom)).to eq 'Fondation SFR' expect(champ.type_de_champ.champ_value_for_export(champ, :nom)).to eq 'Fondation SFR'
expect(champ.for_export(:address)).to eq '16 Rue du Général de Boissieu 75015 Paris' expect(champ.type_de_champ.champ_value_for_export(champ, :address)).to eq '16 Rue du Général de Boissieu 75015 Paris'
expect(champ.for_export(:code_insee)).to eq '75115' expect(champ.type_de_champ.champ_value_for_export(champ, :code_insee)).to eq '75115'
expect(champ.for_export(:departement)).to eq '75 Paris' expect(champ.type_de_champ.champ_value_for_export(champ, :departement)).to eq '75 Paris'
end end
end end
end end

View file

@ -4,7 +4,7 @@ describe Champs::TitreIdentiteChamp do
describe "#for_export" do describe "#for_export" do
let(:champ) { described_class.new } let(:champ) { described_class.new }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_titre_identite)) } before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_titre_identite)) }
subject { champ.for_export } subject { champ.type_de_champ.champ_value_for_export(champ) }
context 'without attached file' do context 'without attached file' do
let(:piece_justificative_file) { double(attached?: true) } let(:piece_justificative_file) { double(attached?: true) }

View file

@ -19,7 +19,7 @@ describe "Dossier en_construction", js: true do
expect(page).not_to have_button("Remplacer") expect(page).not_to have_button("Remplacer")
click_on "Supprimer le fichier toto.txt" click_on "Supprimer le fichier toto.txt"
wait_until { champ.reload.for_export.blank? } wait_until { champ.reload.blank? }
expect(page).not_to have_text("toto.txt") expect(page).not_to have_text("toto.txt")
end end
@ -38,7 +38,7 @@ describe "Dossier en_construction", js: true do
expect(page).to have_selector(input_selector) expect(page).to have_selector(input_selector)
find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf')) find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf'))
wait_until { champ.reload.for_export == 'file.pdf' } wait_until { champ.reload.piece_justificative_file.first&.filename == 'file.pdf' }
expect(page).to have_text("file.pdf") expect(page).to have_text("file.pdf")
end end
end end