feat(attestation): replace tags in preview for v2
This commit is contained in:
parent
d4c4b3a212
commit
40353fee04
12 changed files with 452 additions and 196 deletions
|
@ -5,8 +5,9 @@ module Administrateurs
|
||||||
before_action :retrieve_procedure, :retrieve_attestation_template, :ensure_feature_active
|
before_action :retrieve_procedure, :retrieve_attestation_template, :ensure_feature_active
|
||||||
|
|
||||||
def show
|
def show
|
||||||
json_body = @attestation_template.json_body&.deep_symbolize_keys
|
preview_dossier = @procedure.dossier_for_preview(current_user)
|
||||||
@body = TiptapService.new.to_html(json_body, {})
|
|
||||||
|
@body = @attestation_template.render_attributes_for(dossier: preview_dossier).fetch(:body)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
|
|
|
@ -64,26 +64,19 @@ class AttestationTemplate < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_attributes_for(params = {})
|
def render_attributes_for(params = {})
|
||||||
attributes = {
|
groupe_instructeur = params[:groupe_instructeur]
|
||||||
created_at: Time.zone.now,
|
groupe_instructeur ||= params[:dossier]&.groupe_instructeur
|
||||||
|
|
||||||
|
base_attributes = {
|
||||||
|
created_at: Time.current,
|
||||||
footer: params.fetch(:footer, footer),
|
footer: params.fetch(:footer, footer),
|
||||||
logo: params.fetch(:logo, logo.attached? ? logo : nil)
|
signature: signature_to_render(groupe_instructeur)
|
||||||
}
|
}
|
||||||
|
|
||||||
dossier = params[:dossier]
|
if version == 2
|
||||||
|
render_attributes_for_v2(params, base_attributes)
|
||||||
if dossier.present?
|
|
||||||
attributes.merge({
|
|
||||||
title: replace_tags(title, dossier, escape: false),
|
|
||||||
body: replace_tags(body, dossier, escape: false),
|
|
||||||
signature: signature_to_render(dossier.groupe_instructeur)
|
|
||||||
})
|
|
||||||
else
|
else
|
||||||
attributes.merge({
|
render_attributes_for_v1(params, base_attributes)
|
||||||
title: params.fetch(:title, title),
|
|
||||||
body: params.fetch(:body, body),
|
|
||||||
signature: signature_to_render(params[:groupe_instructeur])
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -113,6 +106,48 @@ class AttestationTemplate < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def render_attributes_for_v1(params, base_attributes)
|
||||||
|
attributes = base_attributes.merge(
|
||||||
|
logo: params.fetch(:logo, logo.attached? ? logo : nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
dossier = params[:dossier]
|
||||||
|
|
||||||
|
if dossier.present?
|
||||||
|
attributes.merge(
|
||||||
|
title: replace_tags(title, dossier, escape: false),
|
||||||
|
body: replace_tags(body, dossier, escape: false)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
attributes.merge(
|
||||||
|
title: params.fetch(:title, title),
|
||||||
|
body: params.fetch(:body, body)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_attributes_for_v2(params, base_attributes)
|
||||||
|
dossier = params[:dossier]
|
||||||
|
|
||||||
|
json = json_body&.deep_symbolize_keys
|
||||||
|
tiptap = TiptapService.new
|
||||||
|
|
||||||
|
if dossier.present?
|
||||||
|
# 2x faster this way than with `replace_tags` which would reparse text
|
||||||
|
used_tags = tiptap.used_tags_and_libelle_for(json.deep_symbolize_keys)
|
||||||
|
substitutions = tags_substitutions(used_tags, dossier, escape: false)
|
||||||
|
body = tiptap.to_html(json, substitutions)
|
||||||
|
|
||||||
|
attributes.merge(
|
||||||
|
body:
|
||||||
|
)
|
||||||
|
else
|
||||||
|
attributes.merge(
|
||||||
|
body: params.fetch(:body) { tiptap.to_html(json) }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def signature_to_render(groupe_instructeur)
|
def signature_to_render(groupe_instructeur)
|
||||||
if groupe_instructeur&.signature&.attached?
|
if groupe_instructeur&.signature&.attached?
|
||||||
groupe_instructeur.signature
|
groupe_instructeur.signature
|
||||||
|
|
|
@ -155,14 +155,14 @@ module TagsSubstitutionConcern
|
||||||
available_for_states: Dossier::SOUMIS
|
available_for_states: Dossier::SOUMIS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'individual_first_name',
|
id: 'individual_last_name',
|
||||||
libelle: 'nom',
|
libelle: 'nom',
|
||||||
description: "nom de l'usager",
|
description: "nom de l'usager",
|
||||||
target: :nom,
|
target: :nom,
|
||||||
available_for_states: Dossier::SOUMIS
|
available_for_states: Dossier::SOUMIS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'individual_last_name',
|
id: 'individual_first_name',
|
||||||
libelle: 'prénom',
|
libelle: 'prénom',
|
||||||
description: "prénom de l'usager",
|
description: "prénom de l'usager",
|
||||||
target: :prenom,
|
target: :prenom,
|
||||||
|
@ -254,6 +254,34 @@ module TagsSubstitutionConcern
|
||||||
used_tags_and_libelle_for(text).map { _1.first.nil? ? _1.second : _1.first }
|
used_tags_and_libelle_for(text).map { _1.first.nil? ? _1.second : _1.first }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tags_substitutions(tokens, dossier, escape: true)
|
||||||
|
# NOTE:
|
||||||
|
# - tokens est un simple Set d'ids (pas la même structure que dans replace_tags)
|
||||||
|
# - dans replace_tags, on fait référence à des tags avec ou sans id, mais pas ici,
|
||||||
|
# a priori inutile car tiptap ne fait référence qu'aux ids.
|
||||||
|
|
||||||
|
@escape_unsafe_tags = escape
|
||||||
|
|
||||||
|
flat_tags = tags_and_datas_list(dossier).each_with_object({}) do |(tags, data), result|
|
||||||
|
next if data.nil?
|
||||||
|
|
||||||
|
valid_tags = tags_for_dossier_state(tags)
|
||||||
|
|
||||||
|
valid_tags.each do |tag|
|
||||||
|
result[tag[:id]] = [tag, data]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tokens.index_with do |token|
|
||||||
|
case flat_tags[token]
|
||||||
|
in tag, data
|
||||||
|
replace_tag(tag, data)
|
||||||
|
else
|
||||||
|
token
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def format_date(date)
|
def format_date(date)
|
||||||
|
@ -323,14 +351,7 @@ module TagsSubstitutionConcern
|
||||||
|
|
||||||
tokens = parse_tags(text)
|
tokens = parse_tags(text)
|
||||||
|
|
||||||
tags_and_datas = [
|
tags_and_datas = tags_and_datas_list(dossier).filter_map do |(tags, data)|
|
||||||
[champ_public_tags(dossier: dossier), dossier.champs_public],
|
|
||||||
[champ_private_tags(dossier: dossier), dossier.champs_private],
|
|
||||||
[dossier_tags, dossier],
|
|
||||||
[ROUTAGE_TAGS, dossier],
|
|
||||||
[INDIVIDUAL_TAGS, dossier.individual],
|
|
||||||
[ENTREPRISE_TAGS, dossier.etablissement&.entreprise]
|
|
||||||
].filter_map do |(tags, data)|
|
|
||||||
data && [tags_for_dossier_state(tags).index_by { _1[:id] }, data]
|
data && [tags_for_dossier_state(tags).index_by { _1[:id] }, data]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -408,4 +429,15 @@ module TagsSubstitutionConcern
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tags_and_datas_list(dossier)
|
||||||
|
[
|
||||||
|
[champ_public_tags(dossier:), dossier.champs_public],
|
||||||
|
[champ_private_tags(dossier:), dossier.champs_private],
|
||||||
|
[dossier_tags, dossier],
|
||||||
|
[ROUTAGE_TAGS, dossier],
|
||||||
|
[INDIVIDUAL_TAGS, dossier.individual],
|
||||||
|
[ENTREPRISE_TAGS, dossier.etablissement&.entreprise]
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -992,6 +992,14 @@ class Procedure < ApplicationRecord
|
||||||
draft_revision.revision_types_de_champ_public.filter { _1.type_de_champ.header_section? }
|
draft_revision.revision_types_de_champ_public.filter { _1.type_de_champ.header_section? }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def dossier_for_preview(user)
|
||||||
|
# Try to use a preview or a dossier filled by current user
|
||||||
|
dossiers.where(for_procedure_preview: true).or(dossiers.not_brouillon)
|
||||||
|
.order(Arel.sql("CASE WHEN for_procedure_preview = True THEN 1 ELSE 0 END DESC,
|
||||||
|
CASE WHEN user_id = #{user.id} THEN 1 ELSE 0 END DESC")) \
|
||||||
|
.first
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def pieces_jointes_list
|
def pieces_jointes_list
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
class TiptapService
|
class TiptapService
|
||||||
def to_html(node, tags)
|
def to_html(node, substitutions = {})
|
||||||
return '' if node.nil?
|
return '' if node.nil?
|
||||||
|
|
||||||
children(node[:content], tags, 0)
|
children(node[:content], substitutions, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def used_tags(node, tags = Set.new)
|
||||||
|
case node
|
||||||
|
in type: 'mention', attrs: { id: }
|
||||||
|
tags << id
|
||||||
|
in { content: } if content.is_a?(Array)
|
||||||
|
content.each { used_tags(_1, tags) }
|
||||||
|
else
|
||||||
|
# noop
|
||||||
|
end
|
||||||
|
|
||||||
|
tags
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -11,11 +24,11 @@ class TiptapService
|
||||||
@body_started = false
|
@body_started = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def children(content, tags, level)
|
def children(content, substitutions, level)
|
||||||
content.map { node_to_html(_1, tags, level) }.join
|
content.map { node_to_html(_1, substitutions, level) }.join
|
||||||
end
|
end
|
||||||
|
|
||||||
def node_to_html(node, tags, level)
|
def node_to_html(node, substitutions, level)
|
||||||
if level == 0 && !@body_started && node[:type] == 'paragraph' && node.key?(:content)
|
if level == 0 && !@body_started && node[:type] == 'paragraph' && node.key?(:content)
|
||||||
@body_started = true
|
@body_started = true
|
||||||
body_start_mark = " class=\"body-start\""
|
body_start_mark = " class=\"body-start\""
|
||||||
|
@ -23,23 +36,23 @@ class TiptapService
|
||||||
|
|
||||||
case node
|
case node
|
||||||
in type: 'header', content:
|
in type: 'header', content:
|
||||||
"<header>#{children(content, tags, level + 1)}</header>"
|
"<header>#{children(content, substitutions, level + 1)}</header>"
|
||||||
in type: 'footer', content:, **rest
|
in type: 'footer', content:, **rest
|
||||||
"<footer#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</footer>"
|
"<footer#{text_align(rest[:attrs])}>#{children(content, substitutions, level + 1)}</footer>"
|
||||||
in type: 'headerColumn', content:, **rest
|
in type: 'headerColumn', content:, **rest
|
||||||
"<div#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</div>"
|
"<div#{text_align(rest[:attrs])}>#{children(content, substitutions, level + 1)}</div>"
|
||||||
in type: 'paragraph', content:, **rest
|
in type: 'paragraph', content:, **rest
|
||||||
"<p#{body_start_mark}#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</p>"
|
"<p#{body_start_mark}#{text_align(rest[:attrs])}>#{children(content, substitutions, level + 1)}</p>"
|
||||||
in type: 'title', content:, **rest
|
in type: 'title', content:, **rest
|
||||||
"<h1#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</h1>"
|
"<h1#{text_align(rest[:attrs])}>#{children(content, substitutions, level + 1)}</h1>"
|
||||||
in type: 'heading', attrs: { level: hlevel, **attrs }, content:
|
in type: 'heading', attrs: { level: hlevel, **attrs }, content:
|
||||||
"<h#{hlevel}#{text_align(attrs)}>#{children(content, tags, level + 1)}</h#{hlevel}>"
|
"<h#{hlevel}#{text_align(attrs)}>#{children(content, substitutions, level + 1)}</h#{hlevel}>"
|
||||||
in type: 'bulletList', content:
|
in type: 'bulletList', content:
|
||||||
"<ul>#{children(content, tags, level + 1)}</ul>"
|
"<ul>#{children(content, substitutions, level + 1)}</ul>"
|
||||||
in type: 'orderedList', content:
|
in type: 'orderedList', content:
|
||||||
"<ol>#{children(content, tags, level + 1)}</ol>"
|
"<ol>#{children(content, substitutions, level + 1)}</ol>"
|
||||||
in type: 'listItem', content:
|
in type: 'listItem', content:
|
||||||
"<li>#{children(content, tags, level + 1)}</li>"
|
"<li>#{children(content, substitutions, level + 1)}</li>"
|
||||||
in type: 'text', text:, **rest
|
in type: 'text', text:, **rest
|
||||||
if rest[:marks].present?
|
if rest[:marks].present?
|
||||||
apply_marks(text, rest[:marks])
|
apply_marks(text, rest[:marks])
|
||||||
|
@ -47,10 +60,12 @@ class TiptapService
|
||||||
text
|
text
|
||||||
end
|
end
|
||||||
in type: 'mention', attrs: { id: }, **rest
|
in type: 'mention', attrs: { id: }, **rest
|
||||||
|
text = substitutions.fetch(id) { "--#{id}--" }
|
||||||
|
|
||||||
if rest[:marks].present?
|
if rest[:marks].present?
|
||||||
apply_marks(tags[id], rest[:marks])
|
apply_marks(text, rest[:marks])
|
||||||
else
|
else
|
||||||
tags[id]
|
text
|
||||||
end
|
end
|
||||||
in { type: type } if ["paragraph", "title", "heading"].include?(type) && !node.key?(:content)
|
in { type: type } if ["paragraph", "title", "heading"].include?(type) && !node.key?(:content)
|
||||||
# noop
|
# noop
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class TagsValidator < ActiveModel::EachValidator
|
class TagsValidator < ActiveModel::EachValidator
|
||||||
def validate_each(record, attribute, value)
|
def validate_each(record, attribute, value)
|
||||||
procedure = record.procedure
|
procedure = record.procedure
|
||||||
tags = record.used_type_de_champ_tags(value || '')
|
tags = record.used_type_de_champ_tags(value.to_s)
|
||||||
|
|
||||||
invalid_tags = tags.filter_map do |(tag, stable_id)|
|
invalid_tags = tags.filter_map do |(tag, stable_id)|
|
||||||
tag if stable_id.nil?
|
tag if stable_id.nil?
|
||||||
|
|
|
@ -102,6 +102,7 @@ namespace :benchmarks do
|
||||||
controller.request = ActionDispatch::TestRequest.create
|
controller.request = ActionDispatch::TestRequest.create
|
||||||
controller.response = ActionDispatch::TestResponse.new
|
controller.response = ActionDispatch::TestResponse.new
|
||||||
controller.request.env['warden'] = warden
|
controller.request.env['warden'] = warden
|
||||||
|
# controller.request.path_parameters[:format] = 'pdf'
|
||||||
|
|
||||||
params = ENV.fetch("PARAMS") { "" }.split(",")
|
params = ENV.fetch("PARAMS") { "" }.split(",")
|
||||||
params.each do |param|
|
params.each do |param|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
describe Administrateurs::AttestationTemplateV2sController, type: :controller do
|
||||||
|
let(:admin) { create(:administrateur) }
|
||||||
|
let(:attestation_template) { build(:attestation_template, :v2) }
|
||||||
|
let!(:procedure) { create(:procedure, administrateur: admin, attestation_template: attestation_template, libelle: "Ma démarche") }
|
||||||
|
let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
|
||||||
|
let(:signature) { fixture_file_upload('spec/fixtures/files/black.png', 'image/png') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(admin.user)
|
||||||
|
Flipper.enable(:attestation_v2)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
subject do
|
||||||
|
get :show, params: { procedure_id: procedure.id }
|
||||||
|
response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'if an attestation template exists on the procedure' do
|
||||||
|
render_views
|
||||||
|
|
||||||
|
context 'with preview dossier' do
|
||||||
|
let!(:dossier) { create(:dossier, :en_construction, procedure:, for_procedure_preview: true) }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to include("Mon titre pour Ma démarche")
|
||||||
|
is_expected.to include("n° #{dossier.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without preview dossier' do
|
||||||
|
it do
|
||||||
|
is_expected.to include("Mon titre pour --dossier_procedure_libelle--")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with logo label' do
|
||||||
|
it do
|
||||||
|
is_expected.to include("Ministère des devs")
|
||||||
|
is_expected.to match(/centered_marianne-\w+\.svg/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with label direction' do
|
||||||
|
let(:attestation_template) { build(:attestation_template, :v2, label_direction: "calé à droite") }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to include("calé à droite")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with footer' do
|
||||||
|
let(:attestation_template) { build(:attestation_template, :v2, footer: "c'est le pied") }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to include("c'est le pied")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with additional logo' do
|
||||||
|
let(:attestation_template) { build(:attestation_template, :v2, logo:) }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to include("Ministère des devs")
|
||||||
|
is_expected.to include("white.png")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with signature' do
|
||||||
|
let(:attestation_template) { build(:attestation_template, :v2, signature:) }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to include("black.png")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,11 +2,46 @@ FactoryBot.define do
|
||||||
factory :attestation_template do
|
factory :attestation_template do
|
||||||
title { 'title' }
|
title { 'title' }
|
||||||
body { 'body' }
|
body { 'body' }
|
||||||
|
json_body { nil }
|
||||||
footer { 'footer' }
|
footer { 'footer' }
|
||||||
activated { true }
|
activated { true }
|
||||||
|
version { 1 }
|
||||||
|
official_layout { true }
|
||||||
|
label_direction { nil }
|
||||||
|
label_logo { nil }
|
||||||
association :procedure
|
association :procedure
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :v2 do
|
||||||
|
version { 2 }
|
||||||
|
body { nil }
|
||||||
|
title { nil }
|
||||||
|
label_logo { "Ministère des devs" }
|
||||||
|
|
||||||
|
json_body do
|
||||||
|
{
|
||||||
|
"type" => "doc",
|
||||||
|
"content" => [
|
||||||
|
{
|
||||||
|
"type" => "header", "content" => [
|
||||||
|
{ "type" => "headerColumn", "attrs" => { "textAlign" => "left" }, "content" => [{ "type" => "paragraph", "attrs" => { "textAlign" => "left" } }] },
|
||||||
|
{ "type" => "headerColumn", "attrs" => { "textAlign" => "left" }, "content" => [{ "type" => "paragraph", "attrs" => { "textAlign" => "left" } }] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "type" => "title", "attrs" => { "textAlign" => "center" }, "content" => [{ "text" => "Mon titre pour ", "type" => "text" }, { "type" => "mention", "attrs" => { "id" => "dossier_procedure_libelle", "label" => "libellé démarche" } }] },
|
||||||
|
{ "type" => "paragraph", "attrs" => { "textAlign" => "left" }, "content" => [{ "text" => "Dossier: n° ", "type" => "text" }, { "type" => "mention", "attrs" => { "id" => "dossier_number", "label" => "numéro du dossier" } }] },
|
||||||
|
{
|
||||||
|
"type" => "paragraph",
|
||||||
|
"content" => [
|
||||||
|
{ "text" => "Nom: ", "type" => "text" }, { "type" => "mention", "attrs" => { "id" => "individual_last_name", "label" => "prénom" } }, { "text" => " ", "type" => "text" },
|
||||||
|
{ "type" => "mention", "attrs" => { "id" => "individual_first_name", "label" => "nom" } }, { "text" => " ", "type" => "text" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
trait :with_files do
|
trait :with_files do
|
||||||
logo { Rack::Test::UploadedFile.new('spec/fixtures/files/logo_test_procedure.png', 'image/png') }
|
logo { Rack::Test::UploadedFile.new('spec/fixtures/files/logo_test_procedure.png', 'image/png') }
|
||||||
signature { Rack::Test::UploadedFile.new('spec/fixtures/files/logo_test_procedure.png', 'image/png') }
|
signature { Rack::Test::UploadedFile.new('spec/fixtures/files/logo_test_procedure.png', 'image/png') }
|
||||||
|
|
|
@ -173,5 +173,16 @@ describe AttestationTemplate, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'body v2' do
|
||||||
|
let(:attestation) { create(:attestation_template, :v2) }
|
||||||
|
let(:dossier) { create(:dossier, procedure: attestation.procedure, individual: build(:individual, nom: 'Doe', prenom: 'John')) }
|
||||||
|
|
||||||
|
it do
|
||||||
|
body = attestation.render_attributes_for(dossier: dossier)[:body]
|
||||||
|
expect(body).to include("Mon titre pour #{dossier.procedure.libelle}")
|
||||||
|
expect(body).to include("Doe John")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,6 +32,39 @@ describe TagsSubstitutionConcern, type: :model do
|
||||||
end).new(procedure, state)
|
end).new(procedure, state)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'tags_substitutions' do
|
||||||
|
let(:individual) { nil }
|
||||||
|
let(:etablissement) { create(:etablissement) }
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, procedure:, individual:, etablissement:) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
let(:tags) { Set.new(["dossier_number"]) }
|
||||||
|
|
||||||
|
subject { template_concern.tags_substitutions(tags, dossier) }
|
||||||
|
|
||||||
|
context 'dossiers metadata' do
|
||||||
|
before { travel_to(Time.zone.local(2024, 1, 15, 12)) }
|
||||||
|
let(:tags) { Set.new(["dossier_number", "dossier_depose_at", "dossier_processed_at", "dossier_procedure_libelle"]) }
|
||||||
|
|
||||||
|
it do
|
||||||
|
is_expected.to eq(
|
||||||
|
"dossier_number" => dossier.id.to_s,
|
||||||
|
"dossier_depose_at" => "15/01/2024",
|
||||||
|
"dossier_processed_at" => "",
|
||||||
|
"dossier_procedure_libelle" => procedure.libelle
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the dossier and the procedure has an individual' do
|
||||||
|
let(:for_individual) { true }
|
||||||
|
let(:individual) { Individual.create(nom: 'Adama', prenom: 'William', gender: 'M') }
|
||||||
|
|
||||||
|
let(:tags) { Set.new(['individual_gender', 'individual_last_name']) }
|
||||||
|
|
||||||
|
it { is_expected.to eq({ "individual_gender" => 'M', "individual_last_name" => "Adama" }) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'replace_tags' do
|
describe 'replace_tags' do
|
||||||
let(:individual) { nil }
|
let(:individual) { nil }
|
||||||
let(:etablissement) { create(:etablissement) }
|
let(:etablissement) { create(:etablissement) }
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
RSpec.describe TiptapService do
|
RSpec.describe TiptapService do
|
||||||
describe '.to_html' do
|
|
||||||
let(:json) do
|
let(:json) do
|
||||||
{
|
{
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
|
@ -149,7 +148,9 @@ RSpec.describe TiptapService do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
let(:tags) { { 'name' => 'Paul' } }
|
|
||||||
|
describe '.to_html' do
|
||||||
|
let(:substitutions) { { 'name' => 'Paul' } }
|
||||||
let(:html) do
|
let(:html) do
|
||||||
[
|
[
|
||||||
'<header><div>Left</div><div>Right</div></header>',
|
'<header><div>Left</div><div>Right</div></header>',
|
||||||
|
@ -166,7 +167,13 @@ RSpec.describe TiptapService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns html' do
|
it 'returns html' do
|
||||||
expect(described_class.new.to_html(json, tags)).to eq(html)
|
expect(described_class.new.to_html(json, substitutions)).to eq(html)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#used_tags' do
|
||||||
|
it 'returns used tags' do
|
||||||
|
expect(described_class.new.used_tags(json)).to eq(Set.new(['name']))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue