[#1110] Extract document template concern from attestation template class
This commit is contained in:
parent
34d9408ed3
commit
3dfc37826a
4 changed files with 287 additions and 217 deletions
|
@ -1,5 +1,6 @@
|
|||
class AttestationTemplate < ApplicationRecord
|
||||
include ActionView::Helpers::NumberHelper
|
||||
include TagsSubstitutionConcern
|
||||
|
||||
belongs_to :procedure
|
||||
|
||||
|
@ -11,16 +12,6 @@ class AttestationTemplate < ApplicationRecord
|
|||
|
||||
FILE_MAX_SIZE_IN_MB = 0.5
|
||||
|
||||
def tags
|
||||
if procedure.for_individual?
|
||||
identity_tags = individual_tags
|
||||
else
|
||||
identity_tags = entreprise_tags + etablissement_tags
|
||||
end
|
||||
|
||||
identity_tags + dossier_tags + procedure_type_de_champ_public_private_tags
|
||||
end
|
||||
|
||||
def attestation_for(dossier)
|
||||
Attestation.new(title: replace_tags(title, dossier), pdf: build_pdf(dossier))
|
||||
end
|
||||
|
@ -53,33 +44,6 @@ class AttestationTemplate < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def procedure_type_de_champ_public_private_tags
|
||||
(procedure.types_de_champ + procedure.types_de_champ_private)
|
||||
.map { |tdc| { libelle: tdc.libelle, description: tdc.description } }
|
||||
end
|
||||
|
||||
def dossier_tags
|
||||
[{ libelle: 'motivation', description: '', target: :motivation },
|
||||
{ libelle: 'numéro du dossier', description: '', target: :id }]
|
||||
end
|
||||
|
||||
def individual_tags
|
||||
[{ libelle: 'civilité', description: 'M., Mme', target: :gender },
|
||||
{ libelle: 'nom', description: "nom de l'usager", target: :nom },
|
||||
{ libelle: 'prénom', description: "prénom de l'usager", target: :prenom }]
|
||||
end
|
||||
|
||||
def entreprise_tags
|
||||
[{ libelle: 'SIREN', description: '', target: :siren },
|
||||
{ libelle: 'numéro de TVA intracommunautaire', description: '', target: :numero_tva_intracommunautaire },
|
||||
{ libelle: 'SIRET du siège social', description: '', target: :siret_siege_social },
|
||||
{ libelle: 'raison sociale', description: '', target: :raison_sociale }]
|
||||
end
|
||||
|
||||
def etablissement_tags
|
||||
[{ libelle: 'adresse', description: '', target: :inline_adresse }]
|
||||
end
|
||||
|
||||
def build_pdf(dossier)
|
||||
action_view = ActionView::Base.new(ActionController::Base.view_paths,
|
||||
logo: logo,
|
||||
|
@ -104,51 +68,4 @@ class AttestationTemplate < ApplicationRecord
|
|||
|
||||
pdf
|
||||
end
|
||||
|
||||
def replace_tags(text, dossier)
|
||||
if text.nil?
|
||||
return ''
|
||||
end
|
||||
|
||||
text = replace_type_de_champ_tags(text, procedure.types_de_champ, dossier.champs)
|
||||
text = replace_type_de_champ_tags(text, procedure.types_de_champ_private, dossier.champs_private)
|
||||
|
||||
tags_and_datas = [
|
||||
[dossier_tags, dossier],
|
||||
[individual_tags, dossier.individual],
|
||||
[entreprise_tags, dossier.entreprise],
|
||||
[etablissement_tags, dossier.entreprise&.etablissement]]
|
||||
|
||||
tags_and_datas.inject(text) { |acc, (tags, data)| replace_tags_with_values_from_data(acc, tags, data) }
|
||||
end
|
||||
|
||||
def replace_type_de_champ_tags(text, types_de_champ, dossier_champs)
|
||||
types_de_champ.inject(text) do |acc, tag|
|
||||
champ = dossier_champs
|
||||
.select { |dossier_champ| dossier_champ.libelle == tag[:libelle] }
|
||||
.first
|
||||
|
||||
replace_tag(acc, tag, champ)
|
||||
end
|
||||
end
|
||||
|
||||
def replace_tags_with_values_from_data(text, tags, data)
|
||||
if data.present?
|
||||
tags.inject(text) do |acc, tag|
|
||||
replace_tag(acc, tag, data.send(tag[:target]))
|
||||
end
|
||||
else
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
def replace_tag(text, tag, value)
|
||||
libelle = Regexp.quote(tag[:libelle])
|
||||
|
||||
# allow any kind of space (non-breaking or other) in the tag’s libellé to match any kind of space in the template
|
||||
# (the '\\ |' is there because plain ASCII spaces were escaped by preceding Regexp.quote)
|
||||
libelle.gsub!(/\\ |[[:blank:]]/, "[[:blank:]]")
|
||||
|
||||
text.gsub(/--#{libelle}--/, value.to_s)
|
||||
end
|
||||
end
|
||||
|
|
89
app/models/concerns/tags_substitution_concern.rb
Normal file
89
app/models/concerns/tags_substitution_concern.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
module TagsSubstitutionConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def tags
|
||||
if procedure.for_individual?
|
||||
identity_tags = individual_tags
|
||||
else
|
||||
identity_tags = entreprise_tags + etablissement_tags
|
||||
end
|
||||
|
||||
identity_tags + dossier_tags + procedure_type_de_champ_public_private_tags
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def procedure_type_de_champ_public_private_tags
|
||||
(procedure.types_de_champ + procedure.types_de_champ_private)
|
||||
.map { |tdc| { libelle: tdc.libelle, description: tdc.description } }
|
||||
end
|
||||
|
||||
def dossier_tags
|
||||
[{ libelle: 'motivation', description: '', target: :motivation },
|
||||
{ libelle: 'numéro du dossier', description: '', target: :id }]
|
||||
end
|
||||
|
||||
def individual_tags
|
||||
[{ libelle: 'civilité', description: 'M., Mme', target: :gender },
|
||||
{ libelle: 'nom', description: "nom de l'usager", target: :nom },
|
||||
{ libelle: 'prénom', description: "prénom de l'usager", target: :prenom }]
|
||||
end
|
||||
|
||||
def entreprise_tags
|
||||
[{ libelle: 'SIREN', description: '', target: :siren },
|
||||
{ libelle: 'numéro de TVA intracommunautaire', description: '', target: :numero_tva_intracommunautaire },
|
||||
{ libelle: 'SIRET du siège social', description: '', target: :siret_siege_social },
|
||||
{ libelle: 'raison sociale', description: '', target: :raison_sociale }]
|
||||
end
|
||||
|
||||
def etablissement_tags
|
||||
[{ libelle: 'adresse', description: '', target: :inline_adresse }]
|
||||
end
|
||||
|
||||
def replace_tags(text, dossier)
|
||||
if text.nil?
|
||||
return ''
|
||||
end
|
||||
|
||||
text = replace_type_de_champ_tags(text, procedure.types_de_champ, dossier.champs)
|
||||
text = replace_type_de_champ_tags(text, procedure.types_de_champ_private, dossier.champs_private)
|
||||
|
||||
tags_and_datas = [
|
||||
[dossier_tags, dossier],
|
||||
[individual_tags, dossier.individual],
|
||||
[entreprise_tags, dossier.entreprise],
|
||||
[etablissement_tags, dossier.entreprise&.etablissement]]
|
||||
|
||||
tags_and_datas.inject(text) { |acc, (tags, data)| replace_tags_with_values_from_data(acc, tags, data) }
|
||||
end
|
||||
|
||||
def replace_type_de_champ_tags(text, types_de_champ, dossier_champs)
|
||||
types_de_champ.inject(text) do |acc, tag|
|
||||
champ = dossier_champs
|
||||
.select { |dossier_champ| dossier_champ.libelle == tag[:libelle] }
|
||||
.first
|
||||
|
||||
replace_tag(acc, tag, champ)
|
||||
end
|
||||
end
|
||||
|
||||
def replace_tags_with_values_from_data(text, tags, data)
|
||||
if data.present?
|
||||
tags.inject(text) do |acc, tag|
|
||||
replace_tag(acc, tag, data.send(tag[:target]))
|
||||
end
|
||||
else
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
def replace_tag(text, tag, value)
|
||||
libelle = Regexp.quote(tag[:libelle])
|
||||
|
||||
# allow any kind of space (non-breaking or other) in the tag’s libellé to match any kind of space in the template
|
||||
# (the '\\ |' is there because plain ASCII spaces were escaped by preceding Regexp.quote)
|
||||
libelle.gsub!(/\\ |[[:blank:]]/, "[[:blank:]]")
|
||||
|
||||
text.gsub(/--#{libelle}--/, value.to_s)
|
||||
end
|
||||
end
|
|
@ -146,68 +146,16 @@ describe AttestationTemplate, type: :model do
|
|||
expect(attestation.pdf.filename).to start_with('attestation')
|
||||
end
|
||||
|
||||
context 'when the dossier and the procedure has an individual' do
|
||||
let(:for_individual) { true }
|
||||
let(:individual) { Individual.create(nom: 'nom', prenom: 'prenom', gender: 'Mme') }
|
||||
|
||||
context 'and the template title use the individual tags' do
|
||||
let(:template_title) { '--civilité-- --nom-- --prénom--' }
|
||||
|
||||
it { expect(view_args[:title]).to eq('Mme nom prenom') }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier and the procedure has an entreprise' do
|
||||
let(:for_individual) { false }
|
||||
|
||||
context 'and the template title use the entreprise tags' do
|
||||
let(:template_title) do
|
||||
'--SIREN-- --numéro de TVA intracommunautaire-- --SIRET du siège social-- --raison sociale-- --adresse--'
|
||||
end
|
||||
|
||||
let(:expected_title) do
|
||||
"#{entreprise.siren} #{entreprise.numero_tva_intracommunautaire} #{entreprise.siret_siege_social} #{entreprise.raison_sociale} --adresse--"
|
||||
end
|
||||
|
||||
it { expect(view_args[:title]).to eq(expected_title) }
|
||||
|
||||
context 'and the entreprise has a etablissement with an adresse' do
|
||||
let(:etablissement) { create(:etablissement, adresse: 'adresse') }
|
||||
let(:template_title) { '--adresse--' }
|
||||
|
||||
it { expect(view_args[:title]).to eq(etablissement.inline_adresse) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has a type de champ named libelleA et libelleB' do
|
||||
let(:types_de_champ) do
|
||||
[create(:type_de_champ_public, libelle: 'libelleA'),
|
||||
create(:type_de_champ_public, libelle: 'libelleB')]
|
||||
end
|
||||
|
||||
context 'and the template title is nil' do
|
||||
let(:template_title) { nil }
|
||||
|
||||
it { expect(view_args[:title]).to eq('') }
|
||||
end
|
||||
|
||||
context 'and it is not used in the template title nor body' do
|
||||
it { expect(view_args[:title]).to eq('title') }
|
||||
it { expect(view_args[:body]).to eq('body') }
|
||||
it { expect(view_args[:created_at]).to eq(Time.now) }
|
||||
it { expect(view_args[:logo]).to eq(attestation_template.logo) }
|
||||
it { expect(view_args[:signature]).to eq(attestation_template.signature) }
|
||||
end
|
||||
|
||||
context 'and the are used in the template title and body' do
|
||||
let(:template_title) { 'title --libelleA--' }
|
||||
let(:template_body) { 'body --libelleB--' }
|
||||
|
||||
context 'and their value in the dossier are nil' do
|
||||
it { expect(view_args[:title]).to eq('title ') }
|
||||
end
|
||||
|
||||
context 'and their value in the dossier are not nil' do
|
||||
before do
|
||||
dossier.champs
|
||||
|
@ -227,86 +175,5 @@ describe AttestationTemplate, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier has a motivation' do
|
||||
let(:dossier) { create(:dossier, motivation: 'motivation') }
|
||||
|
||||
context 'and the title has some dossier tags' do
|
||||
let(:template_title) { 'title --motivation-- --numéro du dossier--' }
|
||||
|
||||
it { expect(view_args[:title]).to eq("title motivation #{dossier.id}") }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has a type de champ prive named libelleA' do
|
||||
let(:types_de_champ_private) { [create(:type_de_champ_private, libelle: 'libelleA')] }
|
||||
|
||||
context 'and the are used in the template title' do
|
||||
let(:template_title) { 'title --libelleA--' }
|
||||
|
||||
context 'and its value in the dossier are not nil' do
|
||||
before { dossier.champs_private.first.update_attributes(value: 'libelle1') }
|
||||
|
||||
it { expect(view_args[:title]).to eq('title libelle1') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has 2 types de champ date and datetime' do
|
||||
let(:types_de_champ) do
|
||||
[create(:type_de_champ_public, libelle: 'date', type_champ: 'date'),
|
||||
create(:type_de_champ_public, libelle: 'datetime', type_champ: 'datetime')]
|
||||
end
|
||||
|
||||
context 'and the are used in the template title' do
|
||||
let(:template_title) { 'title --date-- --datetime--' }
|
||||
|
||||
context 'and its value in the dossier are not nil' do
|
||||
before do
|
||||
dossier.champs
|
||||
.select { |champ| champ.type_champ == 'date' }
|
||||
.first
|
||||
.update_attributes(value: '2017-04-15')
|
||||
|
||||
dossier.champs
|
||||
.select { |champ| champ.type_champ == 'datetime' }
|
||||
.first
|
||||
.update_attributes(value: '13/09/2017 09:00')
|
||||
end
|
||||
|
||||
it { expect(view_args[:title]).to eq('title 15/04/2017 13/09/2017 09:00') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "match breaking and non breaking spaces" do
|
||||
before { dossier.champs.first.update_attributes(value: 'valeur') }
|
||||
|
||||
shared_examples "treat all kinds of space as equivalent" do
|
||||
context 'and the champ has a non breaking space' do
|
||||
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'mon tag')] }
|
||||
|
||||
it { expect(view_args[:body]).to eq('body valeur') }
|
||||
end
|
||||
|
||||
context 'and the champ has an ordinary space' do
|
||||
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'mon tag')] }
|
||||
|
||||
it { expect(view_args[:body]).to eq('body valeur') }
|
||||
end
|
||||
end
|
||||
|
||||
context "when the tag has a non breaking space" do
|
||||
let(:template_body) { 'body --mon tag--' }
|
||||
|
||||
it_behaves_like "treat all kinds of space as equivalent"
|
||||
end
|
||||
|
||||
context "when the tag has an ordinary space" do
|
||||
let(:template_body) { 'body --mon tag--' }
|
||||
|
||||
it_behaves_like "treat all kinds of space as equivalent"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
197
spec/models/concern/tags_substitution_concern_spec.rb
Normal file
197
spec/models/concern/tags_substitution_concern_spec.rb
Normal file
|
@ -0,0 +1,197 @@
|
|||
describe TagsSubstitutionConcern, type: :model do
|
||||
let(:types_de_champ) { [] }
|
||||
let(:types_de_champ_private) { [] }
|
||||
let(:for_individual) { false }
|
||||
|
||||
let(:procedure) do
|
||||
create(:procedure,
|
||||
types_de_champ: types_de_champ,
|
||||
types_de_champ_private: types_de_champ_private,
|
||||
for_individual: for_individual)
|
||||
end
|
||||
|
||||
let(:template_concern) do
|
||||
(Class.new do
|
||||
include TagsSubstitutionConcern
|
||||
public :replace_tags
|
||||
|
||||
def initialize(p)
|
||||
@procedure = p
|
||||
end
|
||||
|
||||
def procedure
|
||||
@procedure
|
||||
end
|
||||
end).new(procedure)
|
||||
end
|
||||
|
||||
describe 'replace_tags' do
|
||||
let(:individual) { nil }
|
||||
let(:etablissement) { nil }
|
||||
let(:entreprise) { create(:entreprise, etablissement: etablissement) }
|
||||
let!(:dossier) { create(:dossier, procedure: procedure, individual: individual, entreprise: entreprise) }
|
||||
|
||||
before { Timecop.freeze(Time.now) }
|
||||
|
||||
subject { template_concern.replace_tags(template, dossier) }
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
context 'when the dossier and the procedure has an individual' do
|
||||
let(:for_individual) { true }
|
||||
let(:individual) { Individual.create(nom: 'nom', prenom: 'prenom', gender: 'Mme') }
|
||||
|
||||
context 'and the template use the individual tags' do
|
||||
let(:template) { '--civilité-- --nom-- --prénom--' }
|
||||
|
||||
it { is_expected.to eq('Mme nom prenom') }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier and the procedure has an entreprise' do
|
||||
let(:for_individual) { false }
|
||||
|
||||
context 'and the template use the entreprise tags' do
|
||||
let(:template) do
|
||||
'--SIREN-- --numéro de TVA intracommunautaire-- --SIRET du siège social-- --raison sociale-- --adresse--'
|
||||
end
|
||||
|
||||
let(:expected_text) do
|
||||
"#{entreprise.siren} #{entreprise.numero_tva_intracommunautaire} #{entreprise.siret_siege_social} #{entreprise.raison_sociale} --adresse--"
|
||||
end
|
||||
|
||||
it { is_expected.to eq(expected_text) }
|
||||
|
||||
context 'and the entreprise has a etablissement with an adresse' do
|
||||
let(:etablissement) { create(:etablissement, adresse: 'adresse') }
|
||||
let(:template) { '--adresse--' }
|
||||
|
||||
it { is_expected.to eq(etablissement.inline_adresse) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has a type de champ named libelleA et libelleB' do
|
||||
let(:types_de_champ) do
|
||||
[create(:type_de_champ_public, libelle: 'libelleA'),
|
||||
create(:type_de_champ_public, libelle: 'libelleB')]
|
||||
end
|
||||
|
||||
context 'and the template is nil' do
|
||||
let(:template) { nil }
|
||||
|
||||
it { is_expected.to eq('') }
|
||||
end
|
||||
|
||||
context 'and it is not used in the template' do
|
||||
let(:template) { '' }
|
||||
it { is_expected.to eq('') }
|
||||
end
|
||||
|
||||
context 'and they are used in the template' do
|
||||
let(:template) { '--libelleA-- --libelleB--' }
|
||||
|
||||
context 'and their value in the dossier are nil' do
|
||||
it { is_expected.to eq(' ') }
|
||||
end
|
||||
|
||||
context 'and their value in the dossier are not nil' do
|
||||
before do
|
||||
dossier.champs
|
||||
.select { |champ| champ.libelle == 'libelleA' }
|
||||
.first
|
||||
.update_attributes(value: 'libelle1')
|
||||
|
||||
dossier.champs
|
||||
.select { |champ| champ.libelle == 'libelleB' }
|
||||
.first
|
||||
.update_attributes(value: 'libelle2')
|
||||
end
|
||||
|
||||
it { is_expected.to eq('libelle1 libelle2') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier has a motivation' do
|
||||
let(:dossier) { create(:dossier, motivation: 'motivation') }
|
||||
|
||||
context 'and the template has some dossier tags' do
|
||||
let(:template) { '--motivation-- --numéro du dossier--' }
|
||||
|
||||
it { is_expected.to eq("motivation #{dossier.id}") }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has a type de champ prive named libelleA' do
|
||||
let(:types_de_champ_private) { [create(:type_de_champ_private, libelle: 'libelleA')] }
|
||||
|
||||
context 'and the are used in the template' do
|
||||
let(:template) { '--libelleA--' }
|
||||
|
||||
context 'and its value in the dossier are not nil' do
|
||||
before { dossier.champs_private.first.update_attributes(value: 'libelle1') }
|
||||
|
||||
it { is_expected.to eq('libelle1') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure has 2 types de champ date and datetime' do
|
||||
let(:types_de_champ) do
|
||||
[create(:type_de_champ_public, libelle: 'date', type_champ: 'date'),
|
||||
create(:type_de_champ_public, libelle: 'datetime', type_champ: 'datetime')]
|
||||
end
|
||||
|
||||
context 'and the are used in the template' do
|
||||
let(:template) { '--date-- --datetime--' }
|
||||
|
||||
context 'and its value in the dossier are not nil' do
|
||||
before do
|
||||
dossier.champs
|
||||
.select { |champ| champ.type_champ == 'date' }
|
||||
.first
|
||||
.update_attributes(value: '2017-04-15')
|
||||
|
||||
dossier.champs
|
||||
.select { |champ| champ.type_champ == 'datetime' }
|
||||
.first
|
||||
.update_attributes(value: '13/09/2017 09:00')
|
||||
end
|
||||
|
||||
it { is_expected.to eq('15/04/2017 13/09/2017 09:00') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "match breaking and non breaking spaces" do
|
||||
before { dossier.champs.first.update_attributes(value: 'valeur') }
|
||||
|
||||
shared_examples "treat all kinds of space as equivalent" do
|
||||
context 'and the champ has a non breaking space' do
|
||||
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'mon tag')] }
|
||||
|
||||
it { is_expected.to eq('valeur') }
|
||||
end
|
||||
|
||||
context 'and the champ has an ordinary space' do
|
||||
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'mon tag')] }
|
||||
|
||||
it { is_expected.to eq('valeur') }
|
||||
end
|
||||
end
|
||||
|
||||
context "when the tag has a non breaking space" do
|
||||
let(:template) { '--mon tag--' }
|
||||
|
||||
it_behaves_like "treat all kinds of space as equivalent"
|
||||
end
|
||||
|
||||
context "when the tag has an ordinary space" do
|
||||
let(:template) { '--mon tag--' }
|
||||
|
||||
it_behaves_like "treat all kinds of space as equivalent"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue