diff --git a/app/models/attestation_template.rb b/app/models/attestation_template.rb index eebfc83f6..a39f93995 100644 --- a/app/models/attestation_template.rb +++ b/app/models/attestation_template.rb @@ -143,14 +143,7 @@ class AttestationTemplate < ApplicationRecord private def used_tags - delimiters_regex = /--(?((?!--).)*)--/ - - # We can't use flat_map as scan will return 3 levels of array, - # using flat_map would give us 2, whereas flatten will - # give us 1, which is what we want - [normalize_tags(title), normalize_tags(body)] - .map { |str| str.scan(delimiters_regex) } - .flatten + used_tags_for(title) + used_tags_for(body) end def build_pdf(dossier) diff --git a/app/models/concerns/tags_substitution_concern.rb b/app/models/concerns/tags_substitution_concern.rb index c92b4e843..72b5e415f 100644 --- a/app/models/concerns/tags_substitution_concern.rb +++ b/app/models/concerns/tags_substitution_concern.rb @@ -139,6 +139,10 @@ module TagsSubstitutionConcern } ] + SHARED_TAG_LIBELLES = (DOSSIER_TAGS + DOSSIER_TAGS_FOR_MAIL + INDIVIDUAL_TAGS + ENTREPRISE_TAGS + ROUTAGE_TAGS).map { |tag| tag[:libelle] } + + TAG_DELIMITERS_REGEX = /--(?((?!--).)*)--/ + def tags if procedure.for_individual? identity_tags = INDIVIDUAL_TAGS @@ -154,6 +158,33 @@ module TagsSubstitutionConcern filter_tags(identity_tags + dossier_tags + champ_public_tags + champ_private_tags + routage_tags) end + def used_type_de_champ_tags(text) + used_tags_for(text, with_libelle: true).filter_map do |(tag, libelle)| + if !tag.in?(SHARED_TAG_LIBELLES) + if tag.start_with?('tdc') + [libelle, tag.gsub('tdc', '').to_i] + else + [tag] + end + end + end + end + + def used_tags_for(text, with_libelle: false) + text, tags = normalize_tags(text) + text + .scan(TAG_DELIMITERS_REGEX) + .flatten + .map do |tag_str| + if with_libelle + tag = tags.find { |tag| tag[:id] == tag_str } + [tag_str, tag ? tag[:libelle] : nil] + else + tag_str + end + end + end + private def format_date(date) @@ -197,7 +228,7 @@ module TagsSubstitutionConcern end def champ_public_tags(dossier: nil) - types_de_champ = dossier&.types_de_champ || procedure.active_revision.types_de_champ_public + types_de_champ = (dossier || procedure.active_revision).types_de_champ_public types_de_champ_tags(types_de_champ, Dossier::SOUMIS) end @@ -219,7 +250,7 @@ module TagsSubstitutionConcern return '' end - text = normalize_tags(text) + text, _ = normalize_tags(text) tags_and_datas = [ [champ_public_tags(dossier: dossier), dossier.champs], @@ -262,8 +293,8 @@ module TagsSubstitutionConcern end def normalize_tags(text) - tags = types_de_champ_tags(procedure.types_de_champ_for_tags, Dossier::SOUMIS) + types_de_champ_tags(procedure.types_de_champ_private_for_tags, Dossier::INSTRUCTION_COMMENCEE) - filter_tags(tags).reduce(text) { |text, tag| normalize_tag(text, tag) } + tags = types_de_champ_tags(procedure.types_de_champ_public_for_tags, Dossier::SOUMIS) + types_de_champ_tags(procedure.types_de_champ_private_for_tags, Dossier::INSTRUCTION_COMMENCEE) + [filter_tags(tags).reduce(text) { |text, tag| normalize_tag(text, tag) }, tags] end def normalize_tag(text, tag) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index c4aae4750..1c247b523 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -435,6 +435,10 @@ class Dossier < ApplicationRecord validates :individual, presence: true, if: -> { revision.procedure.for_individual? } validates :groupe_instructeur, presence: true, if: -> { !brouillon? } + def types_de_champ_public + types_de_champ + end + EXPORT_BATCH_SIZE = 2000 def self.downloadable_sorted_batch diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 305f8b329..e4aefcadd 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -163,35 +163,21 @@ class Procedure < ApplicationRecord end def types_de_champ_for_tags - if brouillon? - draft_types_de_champ - else - TypeDeChamp - .public_only - .fillable - .joins(:revisions) - .where(procedure_revisions: { procedure_id: id }) - .where.not(procedure_revisions: { id: draft_revision_id }) - .where(revision_types_de_champ: { parent_id: nil }) - .order(:created_at) - .uniq - end + TypeDeChamp + .fillable + .joins(:revisions) + .where(procedure_revisions: brouillon? ? { id: draft_revision_id } : { procedure_id: id }) + .where(revision_types_de_champ: { parent_id: nil }) + .order(:created_at) + .distinct(:id) + end + + def types_de_champ_public_for_tags + types_de_champ_for_tags.public_only end def types_de_champ_private_for_tags - if brouillon? - draft_types_de_champ_private - else - TypeDeChamp - .private_only - .fillable - .joins(:revisions) - .where(procedure_revisions: { procedure_id: id }) - .where.not(procedure_revisions: { id: draft_revision_id }) - .where(revision_types_de_champ: { parent_id: nil }) - .order(:created_at) - .uniq - end + types_de_champ_for_tags.private_only end has_many :administrateurs_procedures, dependent: :delete_all diff --git a/spec/models/concern/tags_substitution_concern_spec.rb b/spec/models/concern/tags_substitution_concern_spec.rb index 5b489c8b3..85f295239 100644 --- a/spec/models/concern/tags_substitution_concern_spec.rb +++ b/spec/models/concern/tags_substitution_concern_spec.rb @@ -467,4 +467,34 @@ describe TagsSubstitutionConcern, type: :model do it { is_expected.to include(include({ libelle: 'public' })) } end end + + describe 'used_tags_for' do + let(:text) { 'hello world --public--, --numéro du dossier--, --yolo--' } + subject { template_concern.used_tags_for(text) } + + let(:types_de_champ) do + [ + build(:type_de_champ, libelle: 'public'), + build(:type_de_champ_header_section, libelle: 'entête de section'), + build(:type_de_champ_explication, libelle: 'explication') + ] + end + + it { is_expected.to eq(["tdc#{types_de_champ.first.stable_id}", 'numéro du dossier', 'yolo']) } + end + + describe 'used_type_de_champ_tags' do + let(:text) { 'hello world --public--, --numéro du dossier--, --yolo--' } + subject { template_concern.used_type_de_champ_tags(text) } + + let(:types_de_champ) do + [ + build(:type_de_champ, libelle: 'public'), + build(:type_de_champ_header_section, libelle: 'entête de section'), + build(:type_de_champ_explication, libelle: 'explication') + ] + end + + it { is_expected.to eq([["public", types_de_champ.first.stable_id], ['yolo']]) } + end end