Merge branch 'dev'

This commit is contained in:
gregoirenovel 2018-01-23 16:40:45 +01:00
commit f4b0870921
23 changed files with 399 additions and 136 deletions

View file

@ -45,7 +45,11 @@ class Admin::ProceduresController < AdminController
def hide
procedure = current_administrateur.procedures.find(params[:id])
procedure.hide!
procedure.procedure_path.destroy
# procedure should no longer be reachable so we delete its procedure_path
# that way it is also available for another procedure
# however, sometimes the path has already been deleted (ex: stolen by another procedure),
# so we're not certain the procedure has a procedure_path anymore
procedure.procedure_path.try(:destroy)
flash.notice = "Procédure supprimée, en cas d'erreur contactez nous : contact@tps.apientreprise.fr"
redirect_to admin_procedures_draft_path

View file

@ -7,6 +7,14 @@ class ApplicationController < ActionController::Base
before_action :set_raven_context
before_action :authorize_request_for_profiler
before_action :staging_authenticate
def staging_authenticate
if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) }
request_http_basic_authentication
end
end
def authorize_request_for_profiler
if administration_signed_in?
Rack::MiniProfiler.authorize_request
@ -51,22 +59,54 @@ class ApplicationController < ActionController::Base
private
def set_raven_context
context = { ip_address: request.ip }
logged_models = [
def logged_users
@logged_users ||= [
current_user,
current_gestionnaire,
current_administrateur,
current_administration
].compact
end
context[:email] = logged_models.first&.email
context[:id] = logged_models.first&.id
def logged_user_roles
roles = logged_users.map { |logged_user| logged_user.class.name }
roles.any? ? roles.join(', ') : 'Guest'
end
class_names = logged_models.map { |model| model.class.name }
context[:classes] = class_names.any? ? class_names.join(', ') : 'Guest'
def logged_user_info
logged_user = logged_users.first
if logged_user
{
id: logged_user.id,
email: logged_user.email
}
end
end
def set_raven_context
context = {
ip_address: request.ip,
roles: logged_user_roles
}
context.merge!(logged_user_info || {})
Raven.user_context(context)
end
def append_info_to_payload(payload)
payload.merge!({
user_agent: request.user_agent,
current_user: logged_user_info,
current_user_roles: logged_user_roles
}.compact)
if browser.known?
payload.merge!({
browser: browser.name,
browser_version: browser.version.to_s,
platform: browser.platform.name,
})
end
end
end

View file

@ -2,7 +2,9 @@ module ApplicationHelper
include SanitizeUrl
def sanitize_url(url)
super(url, schemes: ['http', 'https'], replace_evil_with: root_url)
if !url.nil?
super(url, schemes: ['http', 'https'], replace_evil_with: root_url)
end
end
def flash_class(level)

View file

@ -11,6 +11,7 @@ class AttestationTemplate < ApplicationRecord
validates :footer, length: { maximum: 190 }
FILE_MAX_SIZE_IN_MB = 0.5
DOSSIER_STATE = 'accepte'
def attestation_for(dossier)
Attestation.new(title: replace_tags(title, dossier), pdf: build_pdf(dossier))

View file

@ -1,8 +1,6 @@
module MailTemplateConcern
extend ActiveSupport::Concern
include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper
include TagsSubstitutionConcern
def subject_for_dossier(dossier)
@ -13,10 +11,6 @@ module MailTemplateConcern
replace_tags(body, dossier)
end
def tags(is_dossier_termine: self.class.const_get(:IS_DOSSIER_TERMINE))
super
end
module ClassMethods
def default_for_procedure(procedure)
body = ActionController::Base.new.render_to_string(template: self.const_get(:TEMPLATE_NAME))
@ -24,14 +18,7 @@ module MailTemplateConcern
end
end
private
def dossier_tags
super + [{ libelle: 'lien dossier', description: '', lambda: -> (d) { users_dossier_recapitulatif_link(d) } }]
end
def users_dossier_recapitulatif_link(dossier)
url = users_dossier_recapitulatif_url(dossier)
link_to(url, url, target: '_blank')
TagsSubstitutionConcern::DOSSIER_TAGS + TagsSubstitutionConcern::DOSSIER_TAGS_FOR_MAIL
end
end

View file

@ -1,61 +1,123 @@
module TagsSubstitutionConcern
extend ActiveSupport::Concern
def tags(is_dossier_termine: true)
include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper
DOSSIER_TAGS = [
{
libelle: 'motivation',
description: 'Motivation facultative associée à la décision finale dacceptation, refus ou classement sans suite',
target: :motivation,
available_for_states: Dossier::TERMINE
},
{
libelle: 'date de dépôt',
description: 'Date du passage en construction du dossier par lusager',
lambda: -> (d) { format_date(d.en_construction_at) },
available_for_states: Dossier::SOUMIS
},
{
libelle: 'date de passage en instruction',
description: '',
lambda: -> (d) { format_date(d.en_instruction_at) },
available_for_states: Dossier::INSTRUCTION_COMMENCEE
},
{
libelle: 'date de décision',
description: 'Date de la décision dacceptation, refus, ou classement sans suite',
lambda: -> (d) { format_date(d.processed_at) },
available_for_states: Dossier::TERMINE
},
{
libelle: 'libellé procédure',
description: '',
lambda: -> (d) { d.procedure.libelle },
available_for_states: Dossier::SOUMIS
},
{
libelle: 'numéro du dossier',
description: '',
target: :id,
available_for_states: Dossier::SOUMIS
}
]
DOSSIER_TAGS_FOR_MAIL = [
{
libelle: 'lien dossier',
description: '',
lambda: -> (d) { users_dossier_recapitulatif_link(d) },
available_for_states: Dossier::SOUMIS
}
]
INDIVIDUAL_TAGS = [
{
libelle: 'civilité',
description: 'M., Mme',
target: :gender,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'nom',
description: "nom de l'usager",
target: :nom,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'prénom',
description: "prénom de l'usager",
target: :prenom,
available_for_states: Dossier::SOUMIS
}
]
ENTREPRISE_TAGS = [
{
libelle: 'SIREN',
description: '',
target: :siren,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'numéro de TVA intracommunautaire',
description: '',
target: :numero_tva_intracommunautaire,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'SIRET du siège social',
description: '',
target: :siret_siege_social,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'raison sociale',
description: '',
target: :raison_sociale,
available_for_states: Dossier::SOUMIS
},
{
libelle: 'adresse',
description: '',
lambda: -> (e) { e&.etablissement&.inline_adresse },
available_for_states: Dossier::SOUMIS
}
]
def tags
if procedure.for_individual?
identity_tags = individual_tags
identity_tags = INDIVIDUAL_TAGS
else
identity_tags = entreprise_tags + etablissement_tags
identity_tags = ENTREPRISE_TAGS
end
tags = identity_tags + dossier_tags + procedure_type_de_champ_public_private_tags
filter_tags(tags, is_dossier_termine)
filter_tags(identity_tags + dossier_tags + champ_public_tags + champ_private_tags)
end
private
def filter_tags(tags, is_dossier_termine)
if !is_dossier_termine
tags.reject { |tag| tag[:dossier_termine_only] }
else
tags
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: 'Motivation facultative associée à la décision finale dacceptation, refus ou classement sans suite',
target: :motivation,
dossier_termine_only: true
},
{
libelle: 'date de dépôt',
description: 'Date du passage en construction du dossier par lusager',
lambda: -> (d) { format_date(d.en_construction_at) }
},
{
libelle: 'date de passage en instruction',
description: '',
lambda: -> (d) { format_date(d.en_instruction_at) }
},
{
libelle: 'date de décision',
description: 'Date de la décision dacceptation, refus, ou classement sans suite',
lambda: -> (d) { format_date(d.processed_at) },
dossier_termine_only: true
},
{ libelle: 'libellé procédure', description: '', lambda: -> (d) { d.procedure.libelle } },
{ libelle: 'numéro du dossier', description: '', target: :id }
]
end
def format_date(date)
if date.present?
date.localtime.strftime('%d/%m/%Y')
@ -64,25 +126,49 @@ module TagsSubstitutionConcern
end
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 }
]
def users_dossier_recapitulatif_link(dossier)
url = users_dossier_recapitulatif_url(dossier)
link_to(url, url, target: '_blank')
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 }
]
def dossier_tags
# Overridden by MailTemplateConcern
DOSSIER_TAGS
end
def etablissement_tags
[{ libelle: 'adresse', description: '', target: :inline_adresse }]
def filter_tags(tags)
# Implementation note: emails and attestation generations are generally
# triggerred by changes to the dossiers state. The email or attestation
# is generated right after the dossier has reached its new state.
#
# DOSSIER_STATE should be equal to this new state.
#
# For instance, for an email that gets generated for the brouillon->en_construction
# transition, DOSSIER_STATE should equal 'en_construction'.
if !defined?(self.class::DOSSIER_STATE)
raise NameError.new("The class #{self.class.name} includes TagsSubstitutionConcern, it should define the DOSSIER_STATE constant but it does not", :DOSSIER_STATE)
end
tags.select { |tag| tag[:available_for_states].include?(self.class::DOSSIER_STATE) }
end
def champ_public_tags
types_de_champ_tags(procedure.types_de_champ, Dossier::SOUMIS)
end
def champ_private_tags
types_de_champ_tags(procedure.types_de_champ_private, Dossier::INSTRUCTION_COMMENCEE)
end
def types_de_champ_tags(types_de_champ, available_for_states)
types_de_champ.map { |tdc|
{
libelle: tdc.libelle,
description: tdc.description,
available_for_states: available_for_states
}
}
end
def replace_tags(text, dossier)
@ -90,18 +176,17 @@ module TagsSubstitutionConcern
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)
text = replace_type_de_champ_tags(text, filter_tags(champ_public_tags), dossier.champs)
text = replace_type_de_champ_tags(text, filter_tags(champ_private_tags), dossier.champs_private)
tags_and_datas = [
[dossier_tags, dossier],
[individual_tags, dossier.individual],
[entreprise_tags, dossier.entreprise],
[etablissement_tags, dossier.entreprise&.etablissement]
[INDIVIDUAL_TAGS, dossier.individual],
[ENTREPRISE_TAGS, dossier.entreprise]
]
tags_and_datas
.map { |(tags, data)| [filter_tags(tags, dossier.termine?), data] }
.map { |(tags, data)| [filter_tags(tags), data] }
.inject(text) { |acc, (tags, data)| replace_tags_with_values_from_data(acc, tags, data) }
end
@ -121,7 +206,7 @@ module TagsSubstitutionConcern
if tag.key?(:target)
value = data.send(tag[:target])
else
value = tag[:lambda].(data)
value = instance_exec(data, &tag[:lambda])
end
replace_tag(acc, tag, value)
end

View file

@ -10,6 +10,8 @@ class Dossier < ActiveRecord::Base
EN_CONSTRUCTION_OU_INSTRUCTION = %w(en_construction en_instruction)
TERMINE = %w(accepte refuse sans_suite)
INSTRUCTION_COMMENCEE = TERMINE + %w(en_instruction)
SOUMIS = EN_CONSTRUCTION_OU_INSTRUCTION + TERMINE
has_one :etablissement, dependent: :destroy
has_one :entreprise, dependent: :destroy

View file

@ -8,6 +8,6 @@ module Mails
TEMPLATE_NAME = "mails/closed_mail"
DISPLAYED_NAME = "Accusé d'acceptation"
DEFAULT_SUBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été accepté'
IS_DOSSIER_TERMINE = true
DOSSIER_STATE = 'accepte'
end
end

View file

@ -8,6 +8,6 @@ module Mails
TEMPLATE_NAME = "mails/initiated_mail"
DISPLAYED_NAME = 'Accusé de réception'
DEFAULT_SUBJECT = 'Votre dossier TPS nº --numéro du dossier-- a bien été reçu'
IS_DOSSIER_TERMINE = false
DOSSIER_STATE = 'en_construction'
end
end

View file

@ -8,6 +8,6 @@ module Mails
TEMPLATE_NAME = "mails/received_mail"
DISPLAYED_NAME = 'Accusé de passage en instruction'
DEFAULT_SUBJECT = 'Votre dossier TPS nº --numéro du dossier-- va être instruit'
IS_DOSSIER_TERMINE = false
DOSSIER_STATE = 'en_instruction'
end
end

View file

@ -8,6 +8,6 @@ module Mails
TEMPLATE_NAME = "mails/refused_mail"
DISPLAYED_NAME = 'Accusé de rejet du dossier'
DEFAULT_SUBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été refusé'
IS_DOSSIER_TERMINE = true
DOSSIER_STATE = 'refuse'
end
end

View file

@ -8,6 +8,6 @@ module Mails
TEMPLATE_NAME = "mails/without_continuation_mail"
DISPLAYED_NAME = 'Accusé de classement sans suite'
DEFAULT_SUBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été classé sans suite'
IS_DOSSIER_TERMINE = true
DOSSIER_STATE = 'sans_suite'
end
end

View file

@ -0,0 +1,23 @@
class StagingAuthService
CONFIG_PATH = Rails.root.join("/config/basic_auth.yml")
def self.authenticate(username, password)
if enabled?
username == config[:username] && password == config[:password]
else
true
end
end
def self.enabled?
!!config[:enabled]
end
def self.config
if File.exists?(CONFIG_PATH)
YAML.safe_load(File.read(CONFIG_PATH)).symbolize_keys
else
{}
end
end
end

View file

@ -1,6 +1,6 @@
#footer
%p{ class: "copyright col-md-push-#{12-main_container_size} col-md-#{main_container_size} col-lg-push-#{12-main_container_size} col-lg-#{main_container_size} text-muted small" }
= link_to 'SGMAP', "http://etatplateforme.modernisation.gouv.fr"
= link_to 'DINSIC', "http://etatplateforme.modernisation.gouv.fr"
= Time.now.year
\-
= link_to 'Nouveautés', 'https://github.com/betagouv/tps/releases', target: '_blank'

View file

@ -6,7 +6,6 @@ Apipie.configure do |config|
config.markup = Apipie::Markup::Markdown.new
config.default_version = '1.0'
config.validate = false
config.copyright = "© SGMAP"
config.namespaced_resources = true
config.show_all_examples = true

View file

@ -2,4 +2,18 @@ if LogStasher.enabled
LogStasher.add_custom_fields do |fields|
fields[:type] = "tps"
end
LogStasher.watch('process_action.action_controller') do |name, start, finish, id, payload, store|
store[:user_agent] = payload[:user_agent]
store[:browser] = payload[:browser]
store[:browser_version] = payload[:browser_version]
store[:platform] = payload[:platform]
store[:current_user_roles] = payload[:current_user_roles]
if payload[:current_user].present?
store[:current_user_id] = payload[:current_user][:id]
store[:current_user_email] = payload[:current_user][:email]
end
end
end

View file

@ -101,7 +101,7 @@
"order_place": 1,
"description": "description de votre projet"
}
},
},
{
"value": {
"type": "MultiPolygon",
@ -257,8 +257,8 @@
"link": "http://localhost",
"id": 3,
"description": "Demande de subvention à l'intention des associations",
"organisation": "Orga SGMAP",
"direction": "direction SGMAP",
"organisation": "Orga DINSIC",
"direction": "direction DINSIC",
"archived_at": null,
"geographic_information": {
"use_api_carto": true,

View file

@ -559,5 +559,15 @@ describe Admin::ProceduresController, type: :controller do
it { expect(procedure.hidden_at).not_to be_nil }
it { expect(procedure.procedure_path).to be_nil }
end
context "when procedure has no path" do
let!(:procedure) { create :procedure, administrateur: admin }
it { expect{ subject }.not_to raise_error }
it do
subject
expect(procedure.reload.hidden_at).not_to be_nil
end
end
end
end

View file

@ -12,11 +12,12 @@ describe ApplicationController, type: :controller do
end
end
describe 'set_raven_context' do
describe 'set_raven_context and append_info_to_payload' do
let(:current_user) { nil }
let(:current_gestionnaire) { nil }
let(:current_administrateur) { nil }
let(:current_administration) { nil }
let(:payload) { {} }
before do
expect(@controller).to receive(:current_user).and_return(current_user)
@ -26,13 +27,16 @@ describe ApplicationController, type: :controller do
allow(Raven).to receive(:user_context)
@controller.send(:set_raven_context)
@controller.send(:append_info_to_payload, payload)
end
context 'when no one is logged in' do
it do
expect(Raven).to have_received(:user_context)
.with({ ip_address: '0.0.0.0', email: nil, id: nil, classes: 'Guest' })
.with({ ip_address: '0.0.0.0', roles: 'Guest' })
end
it { expect(payload).to eq({ user_agent: 'Rails Testing', current_user_roles: 'Guest' }) }
end
context 'when a user is logged in' do
@ -40,7 +44,18 @@ describe ApplicationController, type: :controller do
it do
expect(Raven).to have_received(:user_context)
.with({ ip_address: '0.0.0.0', email: current_user.email, id: current_user.id, classes: 'User' })
.with({ ip_address: '0.0.0.0', email: current_user.email, id: current_user.id, roles: 'User' })
end
it do
expect(payload).to eq({
user_agent: 'Rails Testing',
current_user: {
id: current_user.id,
email: current_user.email
},
current_user_roles: 'User'
})
end
end
@ -52,7 +67,18 @@ describe ApplicationController, type: :controller do
it do
expect(Raven).to have_received(:user_context)
.with({ ip_address: '0.0.0.0', email: current_user.email, id: current_user.id, classes: 'User, Gestionnaire, Administrateur, Administration' })
.with({ ip_address: '0.0.0.0', email: current_user.email, id: current_user.id, roles: 'User, Gestionnaire, Administrateur, Administration' })
end
it do
expect(payload).to eq({
user_agent: 'Rails Testing',
current_user: {
id: current_user.id,
email: current_user.email
},
current_user_roles: 'User, Gestionnaire, Administrateur, Administration'
})
end
end
end

View file

@ -4,8 +4,8 @@ FactoryGirl.define do
lien_demarche 'http://localhost'
sequence(:libelle) { |n| "Procedure #{n}" }
description "Demande de subvention à l'intention des associations"
organisation "Orga SGMAP"
direction "direction SGMAP"
organisation "Orga DINSIC"
direction "direction DINSIC"
published_at nil
cerfa_flag false
administrateur { create(:administrateur) }

View file

@ -0,0 +1,20 @@
describe ApplicationHelper do
describe "#sanitize_url" do
subject { sanitize_url(url) }
describe 'does nothing on clean url' do
let(:url) { "https://tps.fr/toto" }
it { is_expected.to eq(url) }
end
describe 'clean a dangerous url' do
let(:url) { "javascript:alert('coucou jtai hacké')" }
it { is_expected.to eq(root_url) }
end
describe 'can deal with a nil url' do
let(:url) { nil }
it { is_expected.to be_nil }
end
end
end

View file

@ -4,7 +4,7 @@ describe MailTemplateConcern do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:dossier2) { create(:dossier, procedure: procedure) }
let(:initiated_mail) { Mails::InitiatedMail.default_for_procedure(procedure) }
let(:initiated_mail) { create(:initiated_mail, procedure: procedure) }
shared_examples "can replace tokens in template" do
describe 'with no token to replace' do
@ -47,6 +47,22 @@ describe MailTemplateConcern do
it_behaves_like "can replace tokens in template"
end
describe 'tags' do
describe 'in initiated mail' do
it "does not treat date de passage en instruction as a tag" do
expect(initiated_mail.tags).not_to include(include({ libelle: 'date de passage en instruction' }))
end
end
describe 'in received mail' do
let(:received_mail) { create(:received_mail, procedure: procedure) }
it "treats date de passage en instruction as a tag" do
expect(received_mail.tags).to include(include({ libelle: 'date de passage en instruction' }))
end
end
end
describe '.replace_tags' do
before { initiated_mail.body = "n --numéro du dossier--" }
it "avoids side effects" do

View file

@ -2,6 +2,7 @@ describe TagsSubstitutionConcern, type: :model do
let(:types_de_champ) { [] }
let(:types_de_champ_private) { [] }
let(:for_individual) { false }
let(:state) { 'accepte' }
let(:procedure) do
create(:procedure,
@ -13,17 +14,18 @@ describe TagsSubstitutionConcern, type: :model do
let(:template_concern) do
(Class.new do
include TagsSubstitutionConcern
public :replace_tags
include TagsSubstitutionConcern
public :replace_tags
def initialize(p)
@procedure = p
end
def initialize(p, s)
@procedure = p
self.class.const_set(:DOSSIER_STATE, s)
end
def procedure
@procedure
end
end).new(procedure)
def procedure
@procedure
end
end).new(procedure, state)
end
describe 'replace_tags' do
@ -56,19 +58,13 @@ describe TagsSubstitutionConcern, type: :model do
let(:template) do
'--SIREN-- --numéro de TVA intracommunautaire-- --SIRET du siège social-- --raison sociale-- --adresse--'
end
let(:etablissement) { create(:etablissement) }
let(:expected_text) do
"#{entreprise.siren} #{entreprise.numero_tva_intracommunautaire} #{entreprise.siret_siege_social} #{entreprise.raison_sociale} --adresse--"
"#{entreprise.siren} #{entreprise.numero_tva_intracommunautaire} #{entreprise.siret_siege_social} #{entreprise.raison_sociale} #{etablissement.inline_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
@ -119,8 +115,6 @@ describe TagsSubstitutionConcern, type: :model do
context 'when the dossier has a motivation' do
let(:dossier) { create(:dossier, motivation: 'motivation') }
before { dossier.accepte! }
context 'and the template has some dossier tags' do
let(:template) { '--motivation-- --numéro du dossier--' }
@ -131,10 +125,10 @@ describe TagsSubstitutionConcern, type: :model do
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
context 'and it is used in the template' do
let(:template) { '--libelleA--' }
context 'and its value in the dossier are not nil' do
context 'and its value in the dossier is not nil' do
before { dossier.champs_private.first.update_attributes(value: 'libelle1') }
it { is_expected.to eq('libelle1') }
@ -142,6 +136,28 @@ describe TagsSubstitutionConcern, type: :model do
end
end
context 'when the dossier is en construction' do
let(:state) { 'en_construction' }
let(:template) { '--libelleA--' }
context 'champs privés are not valid tags' do
# The dossier just transitionned from brouillon to en construction,
# so champs private are not valid tags yet
let(:types_de_champ_private) { [create(:type_de_champ_private, libelle: 'libelleA')] }
it { is_expected.to eq('--libelleA--') }
end
context 'champs publics are valid tags' do
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'libelleA')] }
before { dossier.champs.first.update_attributes(value: 'libelle1') }
it { is_expected.to eq('libelle1') }
end
end
context 'when the procedure has 2 types de champ date and datetime' do
let(:types_de_champ) do
[
@ -173,7 +189,6 @@ describe TagsSubstitutionConcern, type: :model do
context "when using a date tag" do
before do
dossier.accepte!
dossier.en_construction_at = DateTime.new(2001, 2, 3)
dossier.en_instruction_at = DateTime.new(2004, 5, 6)
dossier.processed_at = DateTime.new(2007, 8, 9)
@ -237,6 +252,7 @@ describe TagsSubstitutionConcern, type: :model do
context 'when generating a document for a dossier that is not termine' do
let(:dossier) { create(:dossier) }
let(:template) { '--motivation-- --date de décision--' }
let(:state) { 'en_instruction' }
subject { template_concern.replace_tags(template, dossier) }
@ -247,18 +263,36 @@ describe TagsSubstitutionConcern, type: :model do
end
describe 'tags' do
context 'when generating a document for a dossier terminé' do
subject { template_concern.tags }
subject { template_concern.tags }
let(:types_de_champ) { [create(:type_de_champ_public, libelle: 'public')] }
let(:types_de_champ_private) { [create(:type_de_champ_private, libelle: 'privé')] }
context 'when generating a document for a dossier terminé' do
it { is_expected.to include(include({ libelle: 'motivation' })) }
it { is_expected.to include(include({ libelle: 'date de décision' })) }
it { is_expected.to include(include({ libelle: 'public' })) }
it { is_expected.to include(include({ libelle: 'privé' })) }
end
context 'when generating a document for a dossier that is not terminé' do
subject { template_concern.tags(is_dossier_termine: false) }
context 'when generating a document for a dossier en instruction' do
let(:state) { 'en_instruction' }
it { is_expected.not_to include(include({ libelle: 'motivation' })) }
it { is_expected.not_to include(include({ libelle: 'date de décision' })) }
it { is_expected.to include(include({ libelle: 'public' })) }
it { is_expected.to include(include({ libelle: 'privé' })) }
end
context 'when generating a document for a dossier en construction' do
let(:state) { 'en_construction' }
it { is_expected.not_to include(include({ libelle: 'motivation' })) }
it { is_expected.not_to include(include({ libelle: 'date de décision' })) }
it { is_expected.not_to include(include({ libelle: 'privé' })) }
it { is_expected.to include(include({ libelle: 'public' })) }
end
end
end