Merge branch 'dev'

This commit is contained in:
gregoirenovel 2018-01-08 10:02:30 +01:00
commit 9c0fa30d5b
39 changed files with 538 additions and 342 deletions

View file

@ -33,7 +33,6 @@ gem 'haml-rails'
gem 'bootstrap-sass', '~> 3.3.5' gem 'bootstrap-sass', '~> 3.3.5'
# Pagination # Pagination
gem 'will_paginate-bootstrap'
gem 'kaminari' gem 'kaminari'
# Decorators # Decorators

View file

@ -682,9 +682,6 @@ GEM
websocket-driver (0.6.5) websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2) websocket-extensions (0.1.2)
will_paginate (3.1.5)
will_paginate-bootstrap (1.0.1)
will_paginate (>= 3.0.3)
xml-simple (1.1.5) xml-simple (1.1.5)
xpath (2.1.0) xpath (2.1.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
@ -779,7 +776,6 @@ DEPENDENCIES
vcr vcr
web-console web-console
webmock webmock
will_paginate-bootstrap
xray-rails xray-rails
BUNDLED WITH BUNDLED WITH

View file

@ -14,6 +14,9 @@ Téléprocédures Simplifiées, ou TPS pour les intimes, est une plateforme 100
### Développement ### Développement
- Mailcatcher : `gem install mailcatcher` - Mailcatcher : `gem install mailcatcher`
- Hivemind :
* Mac : `brew install hivemind`
* Linux : voir https://github.com/DarthSim/hivemind#installation
### Tests ### Tests
@ -68,6 +71,8 @@ client_id: ''
client_secret: '' client_secret: ''
``` ```
*Note : les valeurs pour ces deux paramètres sont renseignées dans le Keepass*
## Création des comptes initiaux ## Création des comptes initiaux
rails c rails c
@ -81,7 +86,6 @@ client_secret: ''
## Lancement de l'application ## Lancement de l'application
brew install hivemind # Avec Linux voir https://github.com/DarthSim/hivemind#installation
hivemind hivemind
## Programmation des jobs ## Programmation des jobs
@ -125,3 +129,14 @@ Pour exécuter les tests de l'application, plusieurs possibilités :
bundle binstub railties --force bundle binstub railties --force
rake rails:update:bin rake rails:update:bin
## Tâches Super Admin
- ajouter un compte super admin :
`bundle exec rake admin:create_admin[email-du-compte-github@exemple.com]`
- lister les comptes super admin :
`bundle exec rake admin:list`
- supprimer un compte super admin :
`bundle exec rake admin:delete_admin[email-du-compte-github@exemple.com]`

View file

@ -7,7 +7,7 @@ class API::V1::DossiersController < APIController
def index def index
procedure = current_administrateur.procedures.find(params[:procedure_id]) procedure = current_administrateur.procedures.find(params[:procedure_id])
dossiers = procedure.dossiers.state_not_brouillon.paginate(page: params[:page]) dossiers = procedure.dossiers.state_not_brouillon.page(params[:page]).per(per_page)
render json: { dossiers: dossiers.map{ |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }, status: 200 render json: { dossiers: dossiers.map{ |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }, status: 200
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
@ -35,8 +35,12 @@ class API::V1::DossiersController < APIController
def pagination(dossiers) def pagination(dossiers)
{ {
page: dossiers.current_page, page: dossiers.current_page,
resultats_par_page: dossiers.per_page, resultats_par_page: dossiers.limit_value,
nombre_de_page: dossiers.total_pages nombre_de_page: dossiers.total_pages
} }
end end
def per_page # inherited value from will_paginate
12
end
end end

View file

@ -123,8 +123,8 @@ class Backoffice::DossiersController < Backoffice::DossiersListController
notice = "Dossier considéré comme sans suite." notice = "Dossier considéré comme sans suite."
template = dossier.procedure.without_continuation_mail_template template = dossier.procedure.without_continuation_mail_template
when "close" when "close"
dossier.attestation = dossier.build_attestation
dossier.accepte! dossier.accepte!
dossier.attestation = dossier.build_attestation
notice = "Dossier traité avec succès." notice = "Dossier traité avec succès."
template = dossier.procedure.closed_mail_template template = dossier.procedure.closed_mail_template
end end

View file

@ -89,8 +89,8 @@ module NewGestionnaire
notice = "Dossier considéré comme sans suite." notice = "Dossier considéré comme sans suite."
template = procedure.without_continuation_mail_template template = procedure.without_continuation_mail_template
when "accepter" when "accepter"
dossier.attestation = dossier.build_attestation
dossier.accepte! dossier.accepte!
dossier.attestation = dossier.build_attestation
notice = "Dossier traité avec succès." notice = "Dossier traité avec succès."
template = procedure.closed_mail_template template = procedure.closed_mail_template
end end

View file

@ -1,7 +1,7 @@
class DossierDecorator < Draper::Decorator class DossierDecorator < Draper::Decorator
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
delegate :current_page, :per_page, :offset, :total_entries, :total_pages delegate :current_page, :limit_value, :total_pages
delegate_all delegate_all
def first_creation def first_creation

View file

@ -1,3 +1,3 @@
class DossiersDecorator < Draper::CollectionDecorator class DossiersDecorator < Draper::CollectionDecorator
delegate :current_page, :per_page, :offset, :total_entries, :total_pages delegate :current_page, :limit_value, :total_pages
end end

View file

@ -1,3 +1,3 @@
class ProceduresDecorator < Draper::CollectionDecorator class ProceduresDecorator < Draper::CollectionDecorator
delegate :current_page, :per_page, :offset, :total_entries, :total_pages delegate :current_page, :limit_value, :total_pages
end end

View file

@ -1,5 +1,6 @@
class AttestationTemplate < ApplicationRecord class AttestationTemplate < ApplicationRecord
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
include TagsSubstitutionConcern
belongs_to :procedure belongs_to :procedure
@ -11,16 +12,6 @@ class AttestationTemplate < ApplicationRecord
FILE_MAX_SIZE_IN_MB = 0.5 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) def attestation_for(dossier)
Attestation.new(title: replace_tags(title, dossier), pdf: build_pdf(dossier)) Attestation.new(title: replace_tags(title, dossier), pdf: build_pdf(dossier))
end end
@ -53,33 +44,6 @@ class AttestationTemplate < ApplicationRecord
end end
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) def build_pdf(dossier)
action_view = ActionView::Base.new(ActionController::Base.view_paths, action_view = ActionView::Base.new(ActionController::Base.view_paths,
logo: logo, logo: logo,
@ -104,51 +68,4 @@ class AttestationTemplate < ApplicationRecord
pdf pdf
end 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].to_sym))
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 tags 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 end

View file

@ -3,28 +3,7 @@ module MailTemplateConcern
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper include ActionView::Helpers::UrlHelper
include TagsSubstitutionConcern
TAGS = []
TAGS << TAG_NUMERO_DOSSIER = {
name: "numero_dossier",
description: "Permet d'afficher le numéro de dossier de l'utilisateur."
}
TAGS << TAG_LIEN_DOSSIER = {
name: "lien_dossier",
description: "Permet d'afficher un lien vers le dossier de l'utilisateur."
}
TAGS << TAG_LIBELLE_PROCEDURE = {
name: "libelle_procedure",
description: "Permet d'afficher le libellé de la procédure."
}
TAGS << TAG_DATE_DE_DECISION = {
name: "date_de_decision",
description: "Permet d'afficher la date à laquelle la décision finale (acceptation, refus, classement sans suite) sur le dossier a été prise."
}
TAGS << TAG_MOTIVATION = {
name: "motivation",
description: "Permet d'afficher la motivation associée à la décision finale (acceptation, refus, classement sans suite) sur le dossier. Attention, elle est facultative."
}
def object_for_dossier(dossier) def object_for_dossier(dossier)
replace_tags(object, dossier) replace_tags(object, dossier)
@ -34,35 +13,35 @@ module MailTemplateConcern
replace_tags(body, dossier) replace_tags(body, dossier)
end end
def replace_tags(string, dossier) # TODO: remove legacy argument when removing legacy tags
TAGS.inject(string) do |acc, tag| def tags(reject_legacy: true, is_dossier_termine: self.class.const_get(:IS_DOSSIER_TERMINE))
acc.gsub("--#{tag[:name]}--", replace_tag(tag, dossier)) || acc super(is_dossier_termine: is_dossier_termine)
end .reject { |tag| reject_legacy && tag[:is_legacy] }
end end
module ClassMethods module ClassMethods
def default def default_for_procedure(procedure)
body = ActionController::Base.new.render_to_string(template: self.const_get(:TEMPLATE_NAME)) body = ActionController::Base.new.render_to_string(template: self.const_get(:TEMPLATE_NAME))
self.new(object: self.const_get(:DEFAULT_OBJECT), body: body) self.new(object: self.const_get(:DEFAULT_OBJECT), body: body, procedure: procedure)
end end
end end
private private
def replace_tag(tag, dossier) def dossier_tags
case tag super +
when TAG_NUMERO_DOSSIER [{ libelle: 'lien dossier', description: '', lambda: -> (d) { users_dossier_recapitulatif_link(d) } },
dossier.id.to_s # TODO: remove legacy tags
when TAG_LIEN_DOSSIER { libelle: 'numero_dossier', description: '', target: :id, is_legacy: true },
link_to users_dossier_recapitulatif_url(dossier), users_dossier_recapitulatif_url(dossier), target: '_blank' { libelle: 'lien_dossier', description: '', lambda: -> (d) { users_dossier_recapitulatif_link(d) }, is_legacy: true },
when TAG_LIBELLE_PROCEDURE { libelle: 'libelle_procedure', description: '', lambda: -> (d) { d.procedure.libelle }, is_legacy: true },
dossier.procedure.libelle { libelle: 'date_de_decision', description: '',
when TAG_DATE_DE_DECISION lambda: -> (d) { d.processed_at.present? ? d.processed_at.localtime.strftime('%d/%m/%Y') : '' },
dossier.processed_at.present? ? dossier.processed_at.localtime.strftime("%d/%m/%Y") : "" dossier_termine_only: true, is_legacy: true }]
when TAG_MOTIVATION end
dossier.motivation || ""
else def users_dossier_recapitulatif_link(dossier)
'--BALISE_NON_RECONNUE--' url = users_dossier_recapitulatif_url(dossier)
end link_to(url, url, target: '_blank')
end end
end end

View file

@ -0,0 +1,113 @@
module TagsSubstitutionConcern
extend ActiveSupport::Concern
def tags(is_dossier_termine: true)
if procedure.for_individual?
identity_tags = individual_tags
else
identity_tags = entreprise_tags + etablissement_tags
end
tags = identity_tags + dossier_tags + procedure_type_de_champ_public_private_tags
filter_tags(tags, is_dossier_termine)
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écision',
description: 'Date de la décision dacceptation, refus, ou classement sans suite',
lambda: -> (d) { d.processed_at.present? ? d.processed_at.localtime.strftime('%d/%m/%Y') : '' },
dossier_termine_only: true },
{ libelle: 'libellé procédure', description: '', lambda: -> (d) { d.procedure.libelle } },
{ 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
.map { |(tags, data)| [filter_tags(tags, dossier.termine?), data] }
.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|
if tag.key?(:target)
value = data.send(tag[:target])
else
value = tag[:lambda].(data)
end
replace_tag(acc, tag, value)
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 tags 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

View file

@ -2,10 +2,12 @@ module Mails
class ClosedMail < ApplicationRecord class ClosedMail < ApplicationRecord
include MailTemplateConcern include MailTemplateConcern
belongs_to :procedure
SLUG = "closed_mail" SLUG = "closed_mail"
TEMPLATE_NAME = "mails/closed_mail" TEMPLATE_NAME = "mails/closed_mail"
DISPLAYED_NAME = "Accusé d'acceptation" DISPLAYED_NAME = "Accusé d'acceptation"
DEFAULT_OBJECT = 'Votre dossier TPS nº --numero_dossier-- a été accepté' DEFAULT_OBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été accepté'
ALLOWED_TAGS = [TAG_NUMERO_DOSSIER, TAG_LIEN_DOSSIER, TAG_LIBELLE_PROCEDURE, TAG_DATE_DE_DECISION, TAG_MOTIVATION] IS_DOSSIER_TERMINE = true
end end
end end

View file

@ -2,10 +2,12 @@ module Mails
class InitiatedMail < ApplicationRecord class InitiatedMail < ApplicationRecord
include MailTemplateConcern include MailTemplateConcern
belongs_to :procedure
SLUG = "initiated_mail" SLUG = "initiated_mail"
TEMPLATE_NAME = "mails/initiated_mail" TEMPLATE_NAME = "mails/initiated_mail"
DISPLAYED_NAME = 'Accusé de réception' DISPLAYED_NAME = 'Accusé de réception'
DEFAULT_OBJECT = 'Votre dossier TPS nº --numero_dossier-- a bien été reçu' DEFAULT_OBJECT = 'Votre dossier TPS nº --numéro du dossier-- a bien été reçu'
ALLOWED_TAGS = [TAG_NUMERO_DOSSIER, TAG_LIEN_DOSSIER, TAG_LIBELLE_PROCEDURE] IS_DOSSIER_TERMINE = false
end end
end end

View file

@ -2,10 +2,12 @@ module Mails
class ReceivedMail < ApplicationRecord class ReceivedMail < ApplicationRecord
include MailTemplateConcern include MailTemplateConcern
belongs_to :procedure
SLUG = "received_mail" SLUG = "received_mail"
TEMPLATE_NAME = "mails/received_mail" TEMPLATE_NAME = "mails/received_mail"
DISPLAYED_NAME = 'Accusé de passage en instruction' DISPLAYED_NAME = 'Accusé de passage en instruction'
DEFAULT_OBJECT = 'Votre dossier TPS nº --numero_dossier-- va être instruit' DEFAULT_OBJECT = 'Votre dossier TPS nº --numéro du dossier-- va être instruit'
ALLOWED_TAGS = [TAG_NUMERO_DOSSIER, TAG_LIEN_DOSSIER, TAG_LIBELLE_PROCEDURE] IS_DOSSIER_TERMINE = false
end end
end end

View file

@ -2,10 +2,12 @@ module Mails
class RefusedMail < ApplicationRecord class RefusedMail < ApplicationRecord
include MailTemplateConcern include MailTemplateConcern
belongs_to :procedure
SLUG = "refused_mail" SLUG = "refused_mail"
TEMPLATE_NAME = "mails/refused_mail" TEMPLATE_NAME = "mails/refused_mail"
DISPLAYED_NAME = 'Accusé de rejet du dossier' DISPLAYED_NAME = 'Accusé de rejet du dossier'
DEFAULT_OBJECT = 'Votre dossier TPS nº --numero_dossier-- a été refusé' DEFAULT_OBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été refusé'
ALLOWED_TAGS = [TAG_NUMERO_DOSSIER, TAG_LIEN_DOSSIER, TAG_LIBELLE_PROCEDURE, TAG_DATE_DE_DECISION, TAG_MOTIVATION] IS_DOSSIER_TERMINE = true
end end
end end

View file

@ -2,10 +2,12 @@ module Mails
class WithoutContinuationMail < ApplicationRecord class WithoutContinuationMail < ApplicationRecord
include MailTemplateConcern include MailTemplateConcern
belongs_to :procedure
SLUG = "without_continuation" SLUG = "without_continuation"
TEMPLATE_NAME = "mails/without_continuation_mail" TEMPLATE_NAME = "mails/without_continuation_mail"
DISPLAYED_NAME = 'Accusé de classement sans suite' DISPLAYED_NAME = 'Accusé de classement sans suite'
DEFAULT_OBJECT = 'Votre dossier TPS nº --numero_dossier-- a été classé sans suite' DEFAULT_OBJECT = 'Votre dossier TPS nº --numéro du dossier-- a été classé sans suite'
ALLOWED_TAGS = [TAG_NUMERO_DOSSIER, TAG_LIEN_DOSSIER, TAG_LIBELLE_PROCEDURE, TAG_DATE_DE_DECISION, TAG_MOTIVATION] IS_DOSSIER_TERMINE = true
end end
end end

View file

@ -167,23 +167,23 @@ class Procedure < ActiveRecord::Base
end end
def initiated_mail_template def initiated_mail_template
initiated_mail || Mails::InitiatedMail.default initiated_mail || Mails::InitiatedMail.default_for_procedure(self)
end end
def received_mail_template def received_mail_template
received_mail || Mails::ReceivedMail.default received_mail || Mails::ReceivedMail.default_for_procedure(self)
end end
def closed_mail_template def closed_mail_template
closed_mail || Mails::ClosedMail.default closed_mail || Mails::ClosedMail.default_for_procedure(self)
end end
def refused_mail_template def refused_mail_template
refused_mail || Mails::RefusedMail.default refused_mail || Mails::RefusedMail.default_for_procedure(self)
end end
def without_continuation_mail_template def without_continuation_mail_template
without_continuation_mail || Mails::WithoutContinuationMail.default without_continuation_mail || Mails::WithoutContinuationMail.default_for_procedure(self)
end end
def fields def fields

View file

@ -22,9 +22,9 @@
Balise Balise
%th %th
Description Description
- @mail_template.class.const_get(:ALLOWED_TAGS).each do |tag| - @mail_template.tags.each do |tag|
%tr %tr
%td.center %td.center
= "--#{tag[:name]}--" = "--#{tag[:libelle]}--"
%td %td
= tag[:description] = tag[:description]

View file

@ -1,10 +1,10 @@
Bonjour, Bonjour,
%br %br
%br %br
Votre dossier nº --numero_dossier-- a été accepté le --date_de_decision--. Votre dossier nº --numéro du dossier-- a été accepté le --date de décision--.
%br %br
%br %br
A tout moment, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien_dossier-- A tout moment, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien dossier--
%br %br
%br %br
Bonne journée, Bonne journée,

View file

@ -1,10 +1,10 @@
Bonjour, Bonjour,
%br %br
%br %br
Votre administration vous confirme la bonne réception de votre dossier nº --numero_dossier--. Votre administration vous confirme la bonne réception de votre dossier nº --numéro du dossier--.
%br %br
%br %br
A tout moment, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien_dossier-- A tout moment, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien dossier--
%br %br
%br %br
Bonne journée, Bonne journée,

View file

@ -1,7 +1,7 @@
Bonjour, Bonjour,
%br %br
%br %br
Votre administration vous confirme la bonne réception de votre dossier nº --numero_dossier--. Celui-ci sera instruit dans le délai légal déclaré par votre interlocuteur. Votre administration vous confirme la bonne réception de votre dossier nº --numéro du dossier--. Celui-ci sera instruit dans le délai légal déclaré par votre interlocuteur.
%br %br
%br %br
Bonne journée, Bonne journée,

View file

@ -1,10 +1,10 @@
Bonjour, Bonjour,
%br %br
%br %br
Votre dossier nº --numero_dossier-- a été refusé le --date_de_decision--. Votre dossier nº --numéro du dossier-- a été refusé le --date de décision--.
%br %br
%br %br
Pour en savoir plus sur le motif du refus, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien_dossier-- Pour en savoir plus sur le motif du refus, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien dossier--
%br %br
%br %br
Bonne journée, Bonne journée,

View file

@ -1,10 +1,10 @@
Bonjour, Bonjour,
%br %br
%br %br
Votre dossier nº --numero_dossier-- a été classé sans suite le --date_de_decision--. Votre dossier nº --numéro du dossier-- a été classé sans suite le --date de décision--.
%br %br
%br %br
Pour en savoir plus sur les raisons de ce classement sans suite, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien_dossier-- Pour en savoir plus sur les raisons de ce classement sans suite, vous pouvez consulter le contenu de vos dossiers et les éventuels commentaires de l'administration à cette adresse : --lien dossier--
%br %br
%br %br
Bonne journée, Bonne journée,

View file

@ -1,3 +0,0 @@
require 'will_paginate'
WillPaginate.per_page = 12

View file

@ -26,9 +26,6 @@ fr:
no-commentaires: "Il n'y a aucun message dans le fil de discussion, n'hésitez pas à initier le premier." no-commentaires: "Il n'y a aucun message dans le fil de discussion, n'hésitez pas à initier le premier."
depositaire: "Dépositaire" depositaire: "Dépositaire"
pieces: "Pièces jointes" pieces: "Pièces jointes"
will_paginate:
next_label: 'Suivant'
previous_label: 'Précédent'
views: views:
pagination: pagination:
next: Suivant next: Suivant

View file

@ -0,0 +1,22 @@
namespace :'2017_12_21_replace_deprecated_mail_template_tags' do
task set: :environment do
replace_tag('numero_dossier', 'numéro du dossier')
replace_tag('date_de_decision', 'date de décision')
replace_tag('libelle_procedure', 'libellé procédure')
replace_tag('lien_dossier', 'lien dossier')
end
def replace_tag(old_tag, new_tag)
mails = [ Mails::ClosedMail, Mails::InitiatedMail, Mails::ReceivedMail, Mails::RefusedMail, Mails::WithoutContinuationMail]
mails.each do |mail|
replace_tag_in(mail, 'object', old_tag, new_tag)
replace_tag_in(mail, 'body', old_tag, new_tag)
end
end
def replace_tag_in(mail, field, old_tag, new_tag)
mail
.where("#{field} LIKE ?", "%#{old_tag}%")
.update_all("#{field} = REPLACE(#{field}, '#{old_tag}', '#{new_tag}')")
end
end

View file

@ -9,4 +9,19 @@ namespace :admin do
puts "An error occured : #{a.errors.full_messages}" puts "An error occured : #{a.errors.full_messages}"
end end
end end
task list: :environment do
puts "All Administrations :"
Administration.all.pluck(:email).each do |a|
puts a
end
end
task :delete_admin, [:email] => :environment do |t, args|
email = args[:email]
puts "Deleting Administration for #{email}"
a = Administration.find_by(email: email)
a.destroy
puts "#{a.email} deleted"
end
end end

View file

@ -1,8 +1,8 @@
require 'spec_helper' require 'spec_helper'
describe Admin::MailTemplatesController, type: :controller do describe Admin::MailTemplatesController, type: :controller do
let(:initiated_mail) { Mails::InitiatedMail.default }
let(:procedure) { create :procedure } let(:procedure) { create :procedure }
let(:initiated_mail) { Mails::InitiatedMail.default_for_procedure(procedure) }
before do before do
sign_in procedure.administrateur sign_in procedure.administrateur

View file

@ -65,7 +65,7 @@ describe API::V1::DossiersController do
let!(:dossier2) { create(:dossier, :with_entreprise, procedure: procedure, state: 'en_construction') } let!(:dossier2) { create(:dossier, :with_entreprise, procedure: procedure, state: 'en_construction') }
before do before do
allow(Dossier).to receive(:per_page).and_return(1) allow(controller).to receive(:per_page).and_return(1)
end end
describe 'pagination' do describe 'pagination' do

View file

@ -358,11 +358,15 @@ describe Backoffice::DossiersController, type: :controller do
subject { post :process_dossier, params: { process_action: "close", dossier_id: dossier_id, dossier: { motivation: "Yallah" }}} subject { post :process_dossier, params: { process_action: "close", dossier_id: dossier_id, dossier: { motivation: "Yallah" }}}
before do before do
Timecop.freeze(DateTime.now)
expect_any_instance_of(AttestationTemplate) expect_any_instance_of(AttestationTemplate)
.to receive(:attestation_for) .to receive(:attestation_for)
.with(have_attributes(motivation: "Yallah")) .with(have_attributes(motivation: "Yallah", processed_at: DateTime.now))
end end
after { Timecop.return }
it { subject } it { subject }
end end
end end

View file

@ -237,11 +237,15 @@ describe NewGestionnaire::DossiersController, type: :controller do
end end
before do before do
Timecop.freeze(DateTime.now)
expect_any_instance_of(AttestationTemplate) expect_any_instance_of(AttestationTemplate)
.to receive(:attestation_for) .to receive(:attestation_for)
.with(have_attributes(motivation: "Yallah")) .with(have_attributes(motivation: "Yallah", processed_at: DateTime.now))
end end
after { Timecop.return }
it { subject } it { subject }
end end
end end

View file

@ -7,13 +7,12 @@ describe ProceduresDecorator do
create(:procedure, :published, created_at: Time.new(2015, 12, 24, 14, 10)) create(:procedure, :published, created_at: Time.new(2015, 12, 24, 14, 10))
end end
let(:procedure) { Procedure.all.paginate(page: 1) } let(:procedure) { Procedure.all.page(1) }
subject { procedure.decorate } subject { procedure.decorate }
it { expect(subject.current_page).not_to be_nil } it { expect(subject.current_page).not_to be_nil }
it { expect(subject.per_page).not_to be_nil } it { expect(subject.limit_value).not_to be_nil }
it { expect(subject.offset).not_to be_nil } it { expect(subject.count).to eq(3) }
it { expect(subject.total_entries).not_to be_nil }
it { expect(subject.total_pages).not_to be_nil } it { expect(subject.total_pages).not_to be_nil }
end end

View file

@ -1,21 +1,15 @@
FactoryGirl.define do FactoryGirl.define do
factory :mail_template do factory :mail_template, class: Mails::ClosedMail do
object "Object, voila voila" object "Object, voila voila"
body "Blabla ceci est mon body" body "Blabla ceci est mon body"
type 'MailValidated'
trait :dossier_submitted do factory :dossier_submitted_mail_template, class: Mails::ReceivedMail
type 'MailSubmitted'
end
trait :dossier_refused do factory :dossier_refused_mail_template, class: Mails::RefusedMail
type 'MailRefused'
end
trait :dossier_en_instruction do factory :dossier_en_instruction_mail_template, class: Mails::InitiatedMail do
object "[TPS] Accusé de réception pour votre dossier nº --numero_dossier--" object "[TPS] Accusé de réception pour votre dossier nº --numéro du dossier--"
body "Votre administration vous confirme la bonne réception de votre dossier nº --numero_dossier--" body "Votre administration vous confirme la bonne réception de votre dossier nº --numéro du dossier--"
type 'MailReceived'
end end
end end
end end

View file

@ -146,68 +146,16 @@ describe AttestationTemplate, type: :model do
expect(attestation.pdf.filename).to start_with('attestation') expect(attestation.pdf.filename).to start_with('attestation')
end 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 context 'when the procedure has a type de champ named libelleA et libelleB' do
let(:types_de_champ) do let(:types_de_champ) do
[create(:type_de_champ_public, libelle: 'libelleA'), [create(:type_de_champ_public, libelle: 'libelleA'),
create(:type_de_champ_public, libelle: 'libelleB')] create(:type_de_champ_public, libelle: 'libelleB')]
end 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 context 'and the are used in the template title and body' do
let(:template_title) { 'title --libelleA--' } let(:template_title) { 'title --libelleA--' }
let(:template_body) { 'body --libelleB--' } 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 context 'and their value in the dossier are not nil' do
before do before do
dossier.champs dossier.champs
@ -227,92 +175,5 @@ describe AttestationTemplate, type: :model do
end end
end 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') }
context "when the tag contains a non breaking space" do
let(:template_body) { 'body --mon tag--' }
context 'and the champ contains the 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 contains an ordinay space" do
let(:template_body) { 'body --mon tag--' }
context 'and the champ contains 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
end
end end
end end

View file

@ -1,9 +1,10 @@
require 'spec_helper' require 'spec_helper'
describe MailTemplateConcern do describe MailTemplateConcern do
let(:dossier) { create :dossier } let(:procedure) { create(:procedure)}
let(:dossier2) { create :dossier } let(:dossier) { create(:dossier, procedure: procedure) }
let(:initiated_mail) { Mails::InitiatedMail.default } let(:dossier2) { create(:dossier, procedure: procedure) }
let(:initiated_mail) { Mails::InitiatedMail.default_for_procedure(procedure) }
shared_examples "can replace tokens in template" do shared_examples "can replace tokens in template" do
describe 'with no token to replace' do describe 'with no token to replace' do
@ -14,14 +15,14 @@ describe MailTemplateConcern do
end end
describe 'with one token to replace' do describe 'with one token to replace' do
let(:template) { '[TPS] Dossier : --numero_dossier--' } let(:template) { '[TPS] Dossier : --numéro du dossier--' }
it do it do
is_expected.to eq("[TPS] Dossier : #{dossier.id}") is_expected.to eq("[TPS] Dossier : #{dossier.id}")
end end
end end
describe 'with multiples tokens to replace' do describe 'with multiples tokens to replace' do
let(:template) { '[TPS] --numero_dossier-- --libelle_procedure-- --lien_dossier--' } let(:template) { '[TPS] --numéro du dossier-- --libellé procédure-- --lien dossier--' }
it do it do
expected = expected =
"[TPS] #{dossier.id} #{dossier.procedure.libelle} " + "[TPS] #{dossier.id} #{dossier.procedure.libelle} " +
@ -47,10 +48,10 @@ describe MailTemplateConcern do
end end
describe '.replace_tags' do describe '.replace_tags' do
before { initiated_mail.body = "n --numéro du dossier--" }
it "avoids side effects" do it "avoids side effects" do
subject = "n --numero_dossier--" expect(initiated_mail.body_for_dossier(dossier)).to eq("n #{dossier.id}")
expect(initiated_mail.replace_tags(subject, dossier)).to eq("n #{dossier.id}") expect(initiated_mail.body_for_dossier(dossier2)).to eq("n #{dossier2.id}")
expect(initiated_mail.replace_tags(subject, dossier2)).to eq("n #{dossier2.id}")
end end
end end
end end

View file

@ -0,0 +1,241 @@
describe TagsSubstitutionConcern, type: :model do
let(:types_de_champ) { [] }
let(:types_de_champ_private) { [] }
let(:for_individual) { false }
let(:procedure) do
create(:procedure,
libelle: 'Une magnifique procédure',
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') }
before { dossier.accepte! }
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 "when the template has a date de décision tag" do
let(:template) { '--date de décision--' }
before { dossier.accepte! }
it { is_expected.to eq(DateTime.now.localtime.strftime('%d/%m/%Y')) }
end
context "when the template has a libellé procédure tag" do
let(:template) { 'body --libellé procédure--' }
it { is_expected.to eq('body Une magnifique procédure') }
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
context 'when generating a document for a dossier that is not termine' do
let(:dossier) { create(:dossier) }
let(:template) { '--motivation-- --date de décision--' }
subject { template_concern.replace_tags(template, dossier) }
it "does not treat motivation or date de décision as tags" do
is_expected.to eq('--motivation-- --date de décision--')
end
end
end
describe 'tags' do
context 'when generating a document for a dossier terminé' do
subject { template_concern.tags }
it { is_expected.to include(include({ libelle: 'motivation' })) }
it { is_expected.to include(include({ libelle: 'date de décision' })) }
end
context 'when generating a document for a dossier that is not terminé' do
subject { template_concern.tags(is_dossier_termine: false) }
it { is_expected.not_to include(include({ libelle: 'motivation' })) }
it { is_expected.not_to include(include({ libelle: 'date de décision' })) }
end
end
end

View file

@ -12,10 +12,12 @@ describe Procedure do
end end
describe 'initiated_mail' do describe 'initiated_mail' do
subject { create(:procedure) } let(:procedure) { create(:procedure) }
subject { procedure }
context 'when initiated_mail is not customize' do context 'when initiated_mail is not customize' do
it { expect(subject.initiated_mail_template.body).to eq(Mails::InitiatedMail.default.body) } it { expect(subject.initiated_mail_template.body).to eq(Mails::InitiatedMail.default_for_procedure(procedure).body) }
end end
context 'when initiated_mail is customize' do context 'when initiated_mail is customize' do
@ -209,7 +211,7 @@ describe Procedure do
end end
it 'should not duplicate default mail_template' do it 'should not duplicate default mail_template' do
expect(subject.initiated_mail_template.attributes).to eq Mails::InitiatedMail.default.attributes expect(subject.initiated_mail_template.attributes).to eq Mails::InitiatedMail.default_for_procedure(subject).attributes
end end
it 'should not duplicate specific related objects' do it 'should not duplicate specific related objects' do

View file

@ -0,0 +1,26 @@
require 'spec_helper'
describe 'admin/mail_templates/edit.html.haml', type: :view do
let(:procedure) { create(:procedure) }
let(:mail_template) { create(:mail_template, procedure: procedure) }
let(:all_tags) { mail_template.tags(reject_legacy: false) }
before do
allow(view).to receive(:admin_procedure_mail_template_path).and_return("/toto")
allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto")
assign(:mail_template, mail_template)
end
subject { render }
context "Legacy champs are not listed in the page" do
it { expect(all_tags).to include(include({ libelle: 'numero_dossier', is_legacy: true })) }
it { is_expected.not_to include("numero_dossier") }
end
context "Non-legacy champs are listed in the page" do
it { expect(all_tags).to include(include({ libelle: 'numéro du dossier' })) }
it { is_expected.to include("numéro du dossier") }
end
end