diff --git a/app/models/concerns/tags_substitution_concern.rb b/app/models/concerns/tags_substitution_concern.rb index 25da59db8..8a0b11dcf 100644 --- a/app/models/concerns/tags_substitution_concern.rb +++ b/app/models/concerns/tags_substitution_concern.rb @@ -61,42 +61,49 @@ module TagsSubstitutionConcern DOSSIER_TAGS = [ { + id: 'dossier_motivation', libelle: 'motivation', description: 'Motivation facultative associée à la décision finale d’acceptation, refus ou classement sans suite', target: :motivation, available_for_states: Dossier::TERMINE }, { + id: 'dossier_depose_at', libelle: 'date de dépôt', description: 'Date de dépôt du dossier par l’usager', lambda: -> (d) { format_date(d.depose_at) }, available_for_states: Dossier::SOUMIS }, { + id: 'dossier_en_instruction_at', libelle: 'date de passage en instruction', description: '', lambda: -> (d) { format_date(d.en_instruction_at) }, available_for_states: Dossier::INSTRUCTION_COMMENCEE }, { + id: 'dossier_processed_at', libelle: 'date de décision', description: 'Date de la décision d’acceptation, refus, ou classement sans suite', lambda: -> (d) { format_date(d.processed_at) }, available_for_states: Dossier::TERMINE }, { + id: 'dossier_procedure_libelle', libelle: 'libellé démarche', description: '', lambda: -> (d) { d.procedure.libelle }, available_for_states: Dossier::SOUMIS }, { + id: 'dossier_number', libelle: 'numéro du dossier', description: '', target: :id, available_for_states: Dossier::SOUMIS }, { + id: 'dossier_service_name', libelle: 'nom du service', description: 'Le nom du service instructeur qui traite le dossier', lambda: -> (d) { d.procedure.organisation_name || '' }, @@ -106,18 +113,21 @@ module TagsSubstitutionConcern DOSSIER_TAGS_FOR_MAIL = [ { + id: 'dossier_url', libelle: 'lien dossier', description: '', lambda: -> (d) { external_link(dossier_url(d)) }, available_for_states: Dossier::SOUMIS }, { + id: 'dossier_attestation_url', libelle: 'lien attestation', description: '', lambda: -> (d) { external_link(attestation_dossier_url(d)) }, available_for_states: [Dossier.states.fetch(:accepte)] }, { + id: 'dossier_motivation_url', libelle: 'lien document justificatif', description: '', lambda: -> (d) { @@ -133,18 +143,21 @@ module TagsSubstitutionConcern INDIVIDUAL_TAGS = [ { + id: 'individual_gender', libelle: 'civilité', description: 'M., Mme', target: :gender, available_for_states: Dossier::SOUMIS }, { + id: 'individual_first_name', libelle: 'nom', description: "nom de l'usager", target: :nom, available_for_states: Dossier::SOUMIS }, { + id: 'individual_last_name', libelle: 'prénom', description: "prénom de l'usager", target: :prenom, @@ -154,30 +167,35 @@ module TagsSubstitutionConcern ENTREPRISE_TAGS = [ { + id: 'entreprise_siren', libelle: 'SIREN', description: '', target: :siren, available_for_states: Dossier::SOUMIS }, { + id: 'entreprise_numero_tva_intracommunautaire', libelle: 'numéro de TVA intracommunautaire', description: '', target: :numero_tva_intracommunautaire, available_for_states: Dossier::SOUMIS }, { + id: 'entreprise_siret_siege_social', libelle: 'SIRET du siège social', description: '', target: :siret_siege_social, available_for_states: Dossier::SOUMIS }, { + id: 'entreprise_raison_sociale', libelle: 'raison sociale', description: '', target: :raison_sociale, available_for_states: Dossier::SOUMIS }, { + id: 'entreprise_adresse', libelle: 'adresse', description: '', target: :inline_adresse, @@ -187,6 +205,7 @@ module TagsSubstitutionConcern ROUTAGE_TAGS = [ { + id: 'dossier_groupe_instructeur', libelle: 'groupe instructeur', description: 'Le groupe instructeur en charge du dossier', lambda: -> (d) { d.groupe_instructeur&.label }, @@ -194,37 +213,40 @@ module TagsSubstitutionConcern } ] - SHARED_TAG_LIBELLES = (DOSSIER_TAGS + DOSSIER_TAGS_FOR_MAIL + INDIVIDUAL_TAGS + ENTREPRISE_TAGS + ROUTAGE_TAGS).map { |tag| tag[:libelle] } + SHARED_TAG_IDS = (DOSSIER_TAGS + DOSSIER_TAGS_FOR_MAIL + INDIVIDUAL_TAGS + ENTREPRISE_TAGS + ROUTAGE_TAGS).map { _1[:id] } + + def identity_tags + if procedure.for_individual? + INDIVIDUAL_TAGS + else + ENTREPRISE_TAGS + end + end + + def routage_tags + if procedure.routing_enabled? + ROUTAGE_TAGS + else + [] + end + end def tags - if procedure.for_individual? - identity_tags = INDIVIDUAL_TAGS - else - identity_tags = ENTREPRISE_TAGS - end - - routage_tags = [] - if procedure.routing_enabled? - routage_tags = ROUTAGE_TAGS - end - - filter_tags(identity_tags + dossier_tags + champ_public_tags + champ_private_tags + routage_tags) + tags_for_dossier_state(identity_tags + dossier_tags + champ_public_tags + champ_private_tags + routage_tags) end def used_type_de_champ_tags(text) used_tags_and_libelle_for(text).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 + if tag.nil? + [libelle] + elsif !tag.in?(SHARED_TAG_IDS) && tag.start_with?('tdc') + [libelle, tag.gsub(/^tdc/, '').to_i] end end end def used_tags_for(text) - used_tags_and_libelle_for(text).map { |(tag, _)| tag } + used_tags_and_libelle_for(text).map { _1.first.nil? ? _1.second : _1.first } end private @@ -252,7 +274,7 @@ module TagsSubstitutionConcern DOSSIER_TAGS end - def filter_tags(tags) + def tags_for_dossier_state(tags) # Implementation note: emails and attestation generations are generally # triggerred by changes to the dossier’s state. The email or attestation # is generated right after the dossier has reached its new state. @@ -302,7 +324,7 @@ module TagsSubstitutionConcern [INDIVIDUAL_TAGS, dossier.individual], [ENTREPRISE_TAGS, dossier.etablissement&.entreprise] ].filter_map do |(tags, data)| - data && [filter_tags(tags).index_by { _1[:id].presence || _1[:libelle] }, data] + data && [tags_for_dossier_state(tags).index_by { _1[:id] }, data] end tags_and_datas.reduce(tokens) do |tokens, (tags, data)| @@ -337,13 +359,17 @@ module TagsSubstitutionConcern end def procedure_types_de_champ_tags - filter_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)) + tags_for_dossier_state(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) + + identity_tags + dossier_tags + ROUTAGE_TAGS) end def parse_tags(text) tags = procedure_types_de_champ_tags.index_by { _1[:libelle] } - TagsParser.parse(text).map do |token| + # MD5 should be enough and it avoids long key + tokens = Rails.cache.fetch(["parse_tags_v2", Digest::MD5.hexdigest(text)], expires_in: 1.day) { TagsParser.parse(text) } + tokens.map do |token| case token in { tag: tag } if tags.key?(tag) { tag: tag, id: tags.fetch(tag).fetch(:id) } @@ -354,18 +380,15 @@ module TagsSubstitutionConcern end def used_tags_and_libelle_for(text) - # MD5 should be enough and it avoids long key - Rails.cache.fetch(["parse_tags", Digest::MD5.hexdigest(text)], expires_in: 1.day) do - parse_tags(text).filter_map do |token| - case token - in { tag: tag, id: id } - [id, tag] - in { tag: tag } - [tag] - else - nil - end - end + parse_tags(text).filter_map do |token| + case token + in { tag: tag, id: id } + [id, tag] + in { tag: tag } + [nil, tag] + else + nil + end end end end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index 635dc5c6a..0219fe7dc 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -4,7 +4,7 @@ RSpec.describe NotificationMailer, type: :mailer do let(:procedure) { create(:simple_procedure, :with_service) } describe 'send_en_construction_notification' do - let(:dossier) { create(:dossier, :en_construction, :with_individual, user: user, procedure: procedure) } + let(:dossier) { create(:dossier, :en_construction, :with_individual, user: user, procedure:) } subject(:mail) { described_class.send_en_construction_notification(dossier) } @@ -20,7 +20,8 @@ RSpec.describe NotificationMailer, type: :mailer do end context "with a custom template" do - let(:email_template) { create(:initiated_mail, subject: 'Email subject', body: 'Your dossier was received. Thanks.') } + let(:email_template) { create(:initiated_mail, subject: 'Email subject', body: 'Your dossier was received. Thanks.', procedure:) } + before do dossier.procedure.initiated_mail = email_template end @@ -34,8 +35,8 @@ RSpec.describe NotificationMailer, type: :mailer do end describe 'send_en_instruction_notification' do - let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure: procedure) } - let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') } + let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure:) } + let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.', procedure:) } before do dossier.procedure.received_mail = email_template @@ -55,7 +56,7 @@ RSpec.describe NotificationMailer, type: :mailer do end context 'when the template body contains tags' do - let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Hello --nom--, your dossier --lien dossier-- was processed.') } + let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Hello --nom--, your dossier --lien dossier-- was processed.', procedure:) } it 'replaces value tags with the proper value' do expect(mail.body).to have_content(dossier.individual.nom) @@ -67,7 +68,7 @@ RSpec.describe NotificationMailer, type: :mailer do end context 'when the template body contains HTML' do - let(:email_template) { create(:received_mail, body: 'Your dossier was processed. ') } + let(:email_template) { create(:received_mail, body: 'Your dossier was processed. ', procedure:) } it 'allows basic formatting tags' do expect(mail.body).to include('dossier') @@ -85,8 +86,8 @@ RSpec.describe NotificationMailer, type: :mailer do describe 'subject length' do let(:procedure) { create(:simple_procedure, libelle: "My super long title " + ("xo " * 100)) } - let(:dossier) { create(:dossier, :accepte, :with_individual, :with_service, user: user, procedure: procedure) } - let(:email_template) { create(:closed_mail, subject:, body: 'Your dossier was accepted. Thanks.') } + let(:dossier) { create(:dossier, :accepte, :with_individual, :with_service, user: user, procedure:) } + let(:email_template) { create(:closed_mail, subject:, body: 'Your dossier was accepted. Thanks.', procedure:) } before do dossier.procedure.closed_mail = email_template @@ -108,8 +109,8 @@ RSpec.describe NotificationMailer, type: :mailer do describe 'subject with apostrophe' do let(:procedure) { create(:simple_procedure, libelle: "Mon titre avec l'apostrophe") } - let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure: procedure) } - let(:email_template) { create(:received_mail, subject:, body: 'Your dossier was accepted. Thanks.') } + let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure:) } + let(:email_template) { create(:received_mail, subject:, body: 'Your dossier was accepted. Thanks.', procedure:) } before do dossier.procedure.received_mail = email_template diff --git a/spec/models/concern/tags_substitution_concern_spec.rb b/spec/models/concern/tags_substitution_concern_spec.rb index a2fe96f1f..faa4cb187 100644 --- a/spec/models/concern/tags_substitution_concern_spec.rb +++ b/spec/models/concern/tags_substitution_concern_spec.rb @@ -487,7 +487,7 @@ describe TagsSubstitutionConcern, type: :model do ] end - it { is_expected.to eq(["tdc#{procedure.draft_revision.types_de_champ.first.stable_id}", 'numéro du dossier', 'yolo']) } + it { is_expected.to eq(["tdc#{procedure.draft_revision.types_de_champ.first.stable_id}", 'dossier_number', 'yolo']) } end describe 'used_type_de_champ_tags' do