commit
239f776e5d
30 changed files with 311 additions and 196 deletions
|
@ -556,7 +556,7 @@ GEM
|
||||||
http-cookie (>= 1.0.2, < 2.0)
|
http-cookie (>= 1.0.2, < 2.0)
|
||||||
mime-types (>= 1.16, < 4.0)
|
mime-types (>= 1.16, < 4.0)
|
||||||
netrc (~> 0.8)
|
netrc (~> 0.8)
|
||||||
rexml (3.2.4)
|
rexml (3.2.5)
|
||||||
rgeo (2.2.0)
|
rgeo (2.2.0)
|
||||||
rgeo-geojson (2.1.1)
|
rgeo-geojson (2.1.1)
|
||||||
rgeo (>= 1.0.0)
|
rgeo (>= 1.0.0)
|
||||||
|
|
|
@ -211,7 +211,7 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def telecharger_pjs
|
def telecharger_pjs
|
||||||
return head(:forbidden) if !dossier.attachments_downloadable?
|
return head(:forbidden) if !dossier.export_and_attachments_downloadable?
|
||||||
|
|
||||||
files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
|
files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ module Manager
|
||||||
|
|
||||||
def export_mail_brouillons
|
def export_mail_brouillons
|
||||||
dossiers = procedure.dossiers.state_brouillon.includes(:user)
|
dossiers = procedure.dossiers.state_brouillon.includes(:user)
|
||||||
emails = dossiers.map { |d| d.user.email }.sort.uniq
|
emails = dossiers.map { |dossier| dossier.user_email_for(:display) }.sort.uniq
|
||||||
date = Time.zone.now.strftime('%d-%m-%Y')
|
date = Time.zone.now.strftime('%d-%m-%Y')
|
||||||
send_data(emails.join("\n"), :filename => "brouillons-#{procedure.id}-au-#{date}.csv")
|
send_data(emails.join("\n"), :filename => "brouillons-#{procedure.id}-au-#{date}.csv")
|
||||||
end
|
end
|
||||||
|
|
|
@ -143,7 +143,7 @@ module Users
|
||||||
|
|
||||||
if passage_en_construction? && errors.blank?
|
if passage_en_construction? && errors.blank?
|
||||||
@dossier.passer_en_construction!
|
@dossier.passer_en_construction!
|
||||||
NotificationMailer.send_initiated_notification(@dossier).deliver_later
|
NotificationMailer.send_en_construction_notification(@dossier).deliver_later
|
||||||
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
||||||
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@ module Mutations
|
||||||
def validate_blob(blob_id)
|
def validate_blob(blob_id)
|
||||||
begin
|
begin
|
||||||
blob = ActiveStorage::Blob.find_signed(blob_id)
|
blob = ActiveStorage::Blob.find_signed(blob_id)
|
||||||
|
raise ActiveSupport::MessageVerifier::InvalidSignature if blob.nil?
|
||||||
|
|
||||||
# open downloads the file and checks its hash
|
# open downloads the file and checks its hash
|
||||||
blob.open { |f| }
|
blob.open { |f| }
|
||||||
true
|
true
|
||||||
|
|
|
@ -54,7 +54,11 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def usager
|
def usager
|
||||||
Loaders::Record.for(User).load(object.user_id)
|
if object.user_deleted?
|
||||||
|
{ email: object.user_email_for(:display), id: -1 }
|
||||||
|
else
|
||||||
|
Loaders::Record.for(User).load(object.user_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def groupe_instructeur
|
def groupe_instructeur
|
||||||
|
|
|
@ -4,7 +4,8 @@ module ActiveJob::RetryOnTransientErrors
|
||||||
TRANSIENT_ERRORS = [
|
TRANSIENT_ERRORS = [
|
||||||
Excon::Error::InternalServerError,
|
Excon::Error::InternalServerError,
|
||||||
Excon::Error::GatewayTimeout,
|
Excon::Error::GatewayTimeout,
|
||||||
Excon::Error::BadRequest
|
Excon::Error::BadRequest,
|
||||||
|
Excon::Error::Socket
|
||||||
]
|
]
|
||||||
|
|
||||||
included do
|
included do
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class ActiveStorage::DownloadableFile
|
class ActiveStorage::DownloadableFile
|
||||||
def self.create_list_from_dossier(dossier)
|
def self.create_list_from_dossier(dossier)
|
||||||
dossier_export = PiecesJustificativesService.generate_dossier_export(dossier)
|
dossier_export = PiecesJustificativesService.generate_dossier_export(dossier)
|
||||||
pjs = [dossier_export] + PiecesJustificativesService.liste_pieces_justificatives(dossier)
|
pjs = [dossier_export] + PiecesJustificativesService.liste_documents(dossier)
|
||||||
pjs.map do |piece_justificative|
|
pjs.map do |piece_justificative|
|
||||||
[
|
[
|
||||||
piece_justificative,
|
piece_justificative,
|
||||||
|
|
|
@ -13,7 +13,7 @@ class DossierMailer < ApplicationMailer
|
||||||
|
|
||||||
subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »"
|
subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »"
|
||||||
|
|
||||||
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format|
|
mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
|
||||||
format.html { render layout: 'mailers/notifications_layout' }
|
format.html { render layout: 'mailers/notifications_layout' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -25,7 +25,7 @@ class DossierMailer < ApplicationMailer
|
||||||
|
|
||||||
subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})"
|
subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})"
|
||||||
|
|
||||||
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format|
|
mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
|
||||||
format.html { render layout: 'mailers/notifications_layout' }
|
format.html { render layout: 'mailers/notifications_layout' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -49,7 +49,7 @@ class DossierMailer < ApplicationMailer
|
||||||
|
|
||||||
subject = "Votre dossier nº #{@dossier.id} est en train d'être réexaminé"
|
subject = "Votre dossier nº #{@dossier.id} est en train d'être réexaminé"
|
||||||
|
|
||||||
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format|
|
mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
|
||||||
format.html { render layout: 'mailers/notifications_layout' }
|
format.html { render layout: 'mailers/notifications_layout' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -139,7 +139,7 @@ class DossierMailer < ApplicationMailer
|
||||||
@subject = "Attention : votre dossier n'est pas déposé."
|
@subject = "Attention : votre dossier n'est pas déposé."
|
||||||
@dossier = dossier
|
@dossier = dossier
|
||||||
|
|
||||||
mail(to: dossier.user.email, subject: @subject)
|
mail(to: dossier.user_email_for(:notification), subject: @subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
# Preview all emails at http://localhost:3000/rails/mailers/new_attestation_mailer
|
|
||||||
class NewAttestationMailer < ApplicationMailer
|
|
||||||
include Rails.application.routes.url_helpers
|
|
||||||
|
|
||||||
def new_attestation(dossier)
|
|
||||||
to = dossier.user.email
|
|
||||||
subject = "Nouvelle attestation pour votre dossier nº #{dossier.id}"
|
|
||||||
|
|
||||||
mail(to: to, subject: subject, body: body(dossier))
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def body(dossier)
|
|
||||||
<<~HEREDOC
|
|
||||||
Bonjour,
|
|
||||||
|
|
||||||
Votre dossier nº #{dossier.id} (démarche "#{dossier.procedure.libelle}") a subi, à un moment, un "aller-retour" :
|
|
||||||
- Acceptation de votre dossier
|
|
||||||
- Passage en instruction du dossier car besoin de le modifier
|
|
||||||
- Seconde acceptation de votre dossier
|
|
||||||
|
|
||||||
Suite à cette opération, l'attestation liée à votre dossier n'a pas été regénérée.
|
|
||||||
Ce problème est désormais reglé, votre nouvelle attestation est disponible à l'adresse suivante :
|
|
||||||
#{attestation_dossier_url(dossier)}
|
|
||||||
|
|
||||||
Cordialement,
|
|
||||||
|
|
||||||
L’équipe #{APPLICATION_NAME}
|
|
||||||
HEREDOC
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -8,54 +8,63 @@
|
||||||
class NotificationMailer < ApplicationMailer
|
class NotificationMailer < ApplicationMailer
|
||||||
include ActionView::Helpers::SanitizeHelper
|
include ActionView::Helpers::SanitizeHelper
|
||||||
|
|
||||||
|
before_action :set_dossier
|
||||||
|
after_action :create_commentaire_for_notification
|
||||||
|
|
||||||
helper ServiceHelper
|
helper ServiceHelper
|
||||||
helper MailerHelper
|
helper MailerHelper
|
||||||
|
|
||||||
layout 'mailers/notifications_layout'
|
layout 'mailers/notifications_layout'
|
||||||
default from: NO_REPLY_EMAIL
|
default from: NO_REPLY_EMAIL
|
||||||
|
|
||||||
def send_dossier_received(dossier)
|
def send_notification
|
||||||
send_notification(dossier, dossier.procedure.received_mail_template)
|
@service = @dossier.procedure.service
|
||||||
|
@logo_url = attach_logo(@dossier.procedure)
|
||||||
|
@rendered_template = sanitize(@body)
|
||||||
|
|
||||||
|
mail(subject: @subject, to: @email, template_name: 'send_notification')
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_initiated_notification(dossier)
|
def self.send_en_construction_notification(dossier)
|
||||||
send_notification(dossier, dossier.procedure.initiated_mail_template)
|
with(dossier: dossier, state: Dossier.states.fetch(:en_construction)).send_notification
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_closed_notification(dossier)
|
def self.send_en_instruction_notification(dossier)
|
||||||
send_notification(dossier, dossier.procedure.closed_mail_template)
|
with(dossier: dossier, state: Dossier.states.fetch(:en_instruction)).send_notification
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_refused_notification(dossier)
|
def self.send_accepte_notification(dossier)
|
||||||
send_notification(dossier, dossier.procedure.refused_mail_template)
|
with(dossier: dossier, state: Dossier.states.fetch(:accepte)).send_notification
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_without_continuation_notification(dossier)
|
def self.send_refuse_notification(dossier)
|
||||||
send_notification(dossier, dossier.procedure.without_continuation_mail_template)
|
with(dossier: dossier, state: Dossier.states.fetch(:refuse)).send_notification
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_sans_suite_notification(dossier)
|
||||||
|
with(dossier: dossier, state: Dossier.states.fetch(:sans_suite)).send_notification
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def send_notification(dossier, mail_template)
|
def set_dossier
|
||||||
email = dossier.user.email
|
@dossier = params[:dossier]
|
||||||
|
|
||||||
subject = mail_template.subject_for_dossier(dossier)
|
if @dossier.user_deleted?
|
||||||
body = mail_template.body_for_dossier(dossier)
|
mail.perform_deliveries = false
|
||||||
|
else
|
||||||
|
mail_template = @dossier.procedure.mail_template_for(params[:state])
|
||||||
|
|
||||||
create_commentaire_for_notification(dossier, subject, body)
|
@email = @dossier.user_email_for(:notification)
|
||||||
|
@subject = mail_template.subject_for_dossier(@dossier)
|
||||||
@dossier = dossier
|
@body = mail_template.body_for_dossier(@dossier)
|
||||||
@service = dossier.procedure.service
|
@actions = mail_template.actions_for_dossier(@dossier)
|
||||||
@logo_url = attach_logo(dossier.procedure)
|
end
|
||||||
@rendered_template = sanitize(body)
|
|
||||||
@actions = mail_template.actions_for_dossier(dossier)
|
|
||||||
|
|
||||||
mail(subject: subject, to: email, template_name: 'send_notification')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_commentaire_for_notification(dossier, subject, body)
|
def create_commentaire_for_notification
|
||||||
params = { body: ["[#{subject}]", body].join("<br><br>") }
|
body = ["[#{@subject}]", @body].join("<br><br>")
|
||||||
commentaire = CommentaireService.build_with_email(CONTACT_EMAIL, dossier, params)
|
commentaire = CommentaireService.build_with_email(CONTACT_EMAIL, @dossier, body: body)
|
||||||
commentaire.save!
|
commentaire.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
# archived :boolean default(FALSE)
|
# archived :boolean default(FALSE)
|
||||||
# autorisation_donnees :boolean
|
# autorisation_donnees :boolean
|
||||||
# brouillon_close_to_expiration_notice_sent_at :datetime
|
# brouillon_close_to_expiration_notice_sent_at :datetime
|
||||||
|
# deleted_user_email_never_send :string
|
||||||
# en_construction_at :datetime
|
# en_construction_at :datetime
|
||||||
# en_construction_close_to_expiration_notice_sent_at :datetime
|
# en_construction_close_to_expiration_notice_sent_at :datetime
|
||||||
# en_construction_conservation_extension :interval default(0 seconds)
|
# en_construction_conservation_extension :interval default(0 seconds)
|
||||||
|
@ -136,9 +137,9 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
event :repasser_en_instruction, after: :after_repasser_en_instruction do
|
event :repasser_en_instruction, after: :after_repasser_en_instruction do
|
||||||
transitions from: :refuse, to: :en_instruction
|
transitions from: :refuse, to: :en_instruction, guard: :can_repasser_en_instruction?
|
||||||
transitions from: :sans_suite, to: :en_instruction
|
transitions from: :sans_suite, to: :en_instruction, guard: :can_repasser_en_instruction?
|
||||||
transitions from: :accepte, to: :en_instruction
|
transitions from: :accepte, to: :en_instruction, guard: :can_repasser_en_instruction?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -248,6 +249,7 @@ class Dossier < ApplicationRecord
|
||||||
states = opts[:notify_on_closed] ? [:publiee, :close, :depubliee] : [:publiee, :depubliee]
|
states = opts[:notify_on_closed] ? [:publiee, :close, :depubliee] : [:publiee, :depubliee]
|
||||||
joins(:procedure)
|
joins(:procedure)
|
||||||
.where(procedures: { aasm_state: states })
|
.where(procedures: { aasm_state: states })
|
||||||
|
.where.not(user_id: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :brouillon_close_to_expiration, -> do
|
scope :brouillon_close_to_expiration, -> do
|
||||||
|
@ -340,7 +342,7 @@ class Dossier < ApplicationRecord
|
||||||
before_save :build_default_champs, if: Proc.new { revision_id_was.nil? }
|
before_save :build_default_champs, if: Proc.new { revision_id_was.nil? }
|
||||||
before_save :update_search_terms
|
before_save :update_search_terms
|
||||||
|
|
||||||
after_save :send_dossier_received
|
after_save :send_dossier_en_instruction
|
||||||
after_save :send_web_hook
|
after_save :send_web_hook
|
||||||
after_create_commit :send_draft_notification_email
|
after_create_commit :send_draft_notification_email
|
||||||
|
|
||||||
|
@ -348,6 +350,22 @@ class Dossier < ApplicationRecord
|
||||||
validates :individual, presence: true, if: -> { revision.procedure.for_individual? }
|
validates :individual, presence: true, if: -> { revision.procedure.for_individual? }
|
||||||
validates :groupe_instructeur, presence: true, if: -> { !brouillon? }
|
validates :groupe_instructeur, presence: true, if: -> { !brouillon? }
|
||||||
|
|
||||||
|
def user_deleted?
|
||||||
|
user_id.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_email_for(use)
|
||||||
|
if user_deleted?
|
||||||
|
if use == :display
|
||||||
|
deleted_user_email_never_send
|
||||||
|
else
|
||||||
|
raise "Can not send email to discarded user"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
user.email
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def motivation
|
def motivation
|
||||||
return nil if !termine?
|
return nil if !termine?
|
||||||
traitements.any? ? traitements.last.motivation : read_attribute(:motivation)
|
traitements.any? ? traitements.last.motivation : read_attribute(:motivation)
|
||||||
|
@ -414,6 +432,10 @@ class Dossier < ApplicationRecord
|
||||||
brouillon? && procedure.dossier_can_transition_to_en_construction?
|
brouillon? && procedure.dossier_can_transition_to_en_construction?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_repasser_en_instruction?
|
||||||
|
termine? && !user_deleted?
|
||||||
|
end
|
||||||
|
|
||||||
def can_be_updated_by_user?
|
def can_be_updated_by_user?
|
||||||
brouillon? || en_construction?
|
brouillon? || en_construction?
|
||||||
end
|
end
|
||||||
|
@ -427,7 +449,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def messagerie_available?
|
def messagerie_available?
|
||||||
!brouillon? && !archived
|
!brouillon? && !user_deleted? && !archived
|
||||||
end
|
end
|
||||||
|
|
||||||
def en_construction_close_to_expiration?
|
def en_construction_close_to_expiration?
|
||||||
|
@ -580,13 +602,18 @@ class Dossier < ApplicationRecord
|
||||||
administration_emails.each do |email|
|
administration_emails.each do |email|
|
||||||
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
||||||
end
|
end
|
||||||
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
|
|
||||||
|
if !user_deleted?
|
||||||
|
DossierMailer.notify_deletion_to_user(deleted_dossier, user_email_for(:notification)).deliver_later
|
||||||
|
end
|
||||||
|
|
||||||
log_dossier_operation(author, :supprimer, self)
|
log_dossier_operation(author, :supprimer, self)
|
||||||
elsif termine?
|
elsif termine?
|
||||||
deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
|
deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
|
||||||
|
|
||||||
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user.email).deliver_later
|
if !user_deleted?
|
||||||
|
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user_email_for(:notification)).deliver_later
|
||||||
|
end
|
||||||
|
|
||||||
log_dossier_operation(author, :supprimer, self)
|
log_dossier_operation(author, :supprimer, self)
|
||||||
end
|
end
|
||||||
|
@ -651,7 +678,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
save!
|
save!
|
||||||
remove_titres_identite!
|
remove_titres_identite!
|
||||||
NotificationMailer.send_closed_notification(self).deliver_later
|
NotificationMailer.send_accepte_notification(self).deliver_later
|
||||||
send_dossier_decision_to_experts(self)
|
send_dossier_decision_to_experts(self)
|
||||||
log_dossier_operation(instructeur, :accepter, self)
|
log_dossier_operation(instructeur, :accepter, self)
|
||||||
end
|
end
|
||||||
|
@ -666,7 +693,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
save!
|
save!
|
||||||
remove_titres_identite!
|
remove_titres_identite!
|
||||||
NotificationMailer.send_closed_notification(self).deliver_later
|
NotificationMailer.send_accepte_notification(self).deliver_later
|
||||||
log_automatic_dossier_operation(:accepter, self)
|
log_automatic_dossier_operation(:accepter, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -679,7 +706,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
save!
|
save!
|
||||||
remove_titres_identite!
|
remove_titres_identite!
|
||||||
NotificationMailer.send_refused_notification(self).deliver_later
|
NotificationMailer.send_refuse_notification(self).deliver_later
|
||||||
send_dossier_decision_to_experts(self)
|
send_dossier_decision_to_experts(self)
|
||||||
log_dossier_operation(instructeur, :refuser, self)
|
log_dossier_operation(instructeur, :refuser, self)
|
||||||
end
|
end
|
||||||
|
@ -693,7 +720,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
save!
|
save!
|
||||||
remove_titres_identite!
|
remove_titres_identite!
|
||||||
NotificationMailer.send_without_continuation_notification(self).deliver_later
|
NotificationMailer.send_sans_suite_notification(self).deliver_later
|
||||||
send_dossier_decision_to_experts(self)
|
send_dossier_decision_to_experts(self)
|
||||||
log_dossier_operation(instructeur, :classer_sans_suite, self)
|
log_dossier_operation(instructeur, :classer_sans_suite, self)
|
||||||
end
|
end
|
||||||
|
@ -739,7 +766,7 @@ class Dossier < ApplicationRecord
|
||||||
def spreadsheet_columns(with_etablissement: false, types_de_champ:, types_de_champ_private:)
|
def spreadsheet_columns(with_etablissement: false, types_de_champ:, types_de_champ_private:)
|
||||||
columns = [
|
columns = [
|
||||||
['ID', id.to_s],
|
['ID', id.to_s],
|
||||||
['Email', user.email]
|
['Email', user_email_for(:display)]
|
||||||
]
|
]
|
||||||
|
|
||||||
if procedure.for_individual?
|
if procedure.for_individual?
|
||||||
|
@ -834,9 +861,8 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachments_downloadable?
|
def export_and_attachments_downloadable?
|
||||||
PiecesJustificativesService.liste_pieces_justificatives(self).present? \
|
PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
|
||||||
&& PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def linked_dossiers_for(instructeur_or_expert)
|
def linked_dossiers_for(instructeur_or_expert)
|
||||||
|
@ -910,9 +936,9 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_dossier_received
|
def send_dossier_en_instruction
|
||||||
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
|
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
|
||||||
NotificationMailer.send_dossier_received(self).deliver_later
|
NotificationMailer.send_en_instruction_notification(self).deliver_later
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -500,6 +500,23 @@ class Procedure < ApplicationRecord
|
||||||
without_continuation_mail || Mails::WithoutContinuationMail.default_for_procedure(self)
|
without_continuation_mail || Mails::WithoutContinuationMail.default_for_procedure(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mail_template_for(state)
|
||||||
|
case state
|
||||||
|
when Dossier.states.fetch(:en_construction)
|
||||||
|
initiated_mail_template
|
||||||
|
when Dossier.states.fetch(:en_instruction)
|
||||||
|
received_mail_template
|
||||||
|
when Dossier.states.fetch(:accepte)
|
||||||
|
closed_mail_template
|
||||||
|
when Dossier.states.fetch(:refuse)
|
||||||
|
refused_mail_template
|
||||||
|
when Dossier.states.fetch(:sans_suite)
|
||||||
|
without_continuation_mail_template
|
||||||
|
else
|
||||||
|
raise "Unknown dossier state: #{state}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.default_sort
|
def self.default_sort
|
||||||
{
|
{
|
||||||
'table' => 'self',
|
'table' => 'self',
|
||||||
|
|
|
@ -170,18 +170,24 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_be_deleted?
|
def can_be_deleted?
|
||||||
!administrateur? && !instructeur? && !expert? && dossiers.with_discarded.state_instruction_commencee.empty?
|
!administrateur? && !instructeur? && !expert?
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_and_keep_track_dossiers(administration)
|
def delete_and_keep_track_dossiers(administration)
|
||||||
if !can_be_deleted?
|
if !can_be_deleted?
|
||||||
raise "Cannot delete this user because instruction has started for some dossiers"
|
raise "Cannot delete this user because they are also instructeur, expert or administrateur"
|
||||||
end
|
end
|
||||||
|
|
||||||
dossiers.each do |dossier|
|
Invite.where(dossier: dossiers.with_discarded).destroy_all
|
||||||
|
dossiers.state_en_construction.each do |dossier|
|
||||||
dossier.discard_and_keep_track!(administration, :user_removed)
|
dossier.discard_and_keep_track!(administration, :user_removed)
|
||||||
end
|
end
|
||||||
dossiers.with_discarded.destroy_all
|
DossierOperationLog
|
||||||
|
.where(dossier: dossiers.with_discarded.discarded)
|
||||||
|
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||||
|
.destroy_all
|
||||||
|
dossiers.with_discarded.discarded.destroy_all
|
||||||
|
dossiers.update_all(deleted_user_email_never_send: email, user_id: nil)
|
||||||
destroy!
|
destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class PiecesJustificativesService
|
class PiecesJustificativesService
|
||||||
def self.liste_pieces_justificatives(dossier)
|
def self.liste_documents(dossier)
|
||||||
pjs_champs = pjs_for_champs(dossier)
|
pjs_champs = pjs_for_champs(dossier)
|
||||||
pjs_commentaires = pjs_for_commentaires(dossier)
|
pjs_commentaires = pjs_for_commentaires(dossier)
|
||||||
pjs_dossier = pjs_for_dossier(dossier)
|
pjs_dossier = pjs_for_dossier(dossier)
|
||||||
|
@ -8,6 +8,14 @@ class PiecesJustificativesService
|
||||||
.filter(&:attached?)
|
.filter(&:attached?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.liste_pieces_justificatives(dossier)
|
||||||
|
pjs_champs = pjs_for_champs(dossier)
|
||||||
|
pjs_commentaires = pjs_for_commentaires(dossier)
|
||||||
|
|
||||||
|
(pjs_champs + pjs_commentaires)
|
||||||
|
.filter(&:attached?)
|
||||||
|
end
|
||||||
|
|
||||||
def self.pieces_justificatives_total_size(dossier)
|
def self.pieces_justificatives_total_size(dossier)
|
||||||
liste_pieces_justificatives(dossier)
|
liste_pieces_justificatives(dossier)
|
||||||
.sum(&:byte_size)
|
.sum(&:byte_size)
|
||||||
|
|
|
@ -174,7 +174,7 @@ def add_message(pdf, message)
|
||||||
if message.sent_by_system?
|
if message.sent_by_system?
|
||||||
sender = 'Email automatique'
|
sender = 'Email automatique'
|
||||||
elsif message.sent_by?(@dossier.user)
|
elsif message.sent_by?(@dossier.user)
|
||||||
sender = @dossier.user.email
|
sender = @dossier.user_email_for(:display)
|
||||||
end
|
end
|
||||||
|
|
||||||
format_in_2_lines(pdf, "#{sender}, #{try_format_date(message.created_at)}",
|
format_in_2_lines(pdf, "#{sender}, #{try_format_date(message.created_at)}",
|
||||||
|
@ -233,7 +233,7 @@ prawn_document(page_size: "A4") do |pdf|
|
||||||
format_in_2_columns(pdf, 'Informations France Connect', "Le dossier a été déposé par le compte de #{@dossier.france_connect_information.given_name} #{@dossier.france_connect_information.family_name}, authentifié par France Connect le #{@dossier.france_connect_information.updated_at.strftime('%d/%m/%Y')}")
|
format_in_2_columns(pdf, 'Informations France Connect', "Le dossier a été déposé par le compte de #{@dossier.france_connect_information.given_name} #{@dossier.france_connect_information.family_name}, authentifié par France Connect le #{@dossier.france_connect_information.updated_at.strftime('%d/%m/%Y')}")
|
||||||
end
|
end
|
||||||
|
|
||||||
format_in_2_columns(pdf, "Email", @dossier.user.email)
|
format_in_2_columns(pdf, "Email", @dossier.user_email_for(:display))
|
||||||
|
|
||||||
if @dossier.individual.present?
|
if @dossier.individual.present?
|
||||||
add_identite_individual(pdf, @dossier.individual)
|
add_identite_individual(pdf, @dossier.individual)
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
|
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
|
||||||
%span.icon.folder
|
%span.icon.folder
|
||||||
#{avis.dossier.id}
|
#{avis.dossier.id}
|
||||||
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
%td= link_to(avis.dossier.user_email_for(:display), instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
||||||
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
||||||
= paginate(@avis)
|
= paginate(@avis)
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
|
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
|
||||||
%span.icon.folder
|
%span.icon.folder
|
||||||
#{avis.dossier.id}
|
#{avis.dossier.id}
|
||||||
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
%td= link_to(avis.dossier.user_email_for(:display), instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
||||||
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
|
||||||
= paginate(@avis)
|
= paginate(@avis)
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -12,16 +12,15 @@
|
||||||
%li
|
%li
|
||||||
= link_to "Export GeoJSON", geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
= link_to "Export GeoJSON", geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||||
|
|
||||||
- if PiecesJustificativesService.liste_pieces_justificatives(dossier).present?
|
%span.dropdown.print-menu-opener
|
||||||
%span.dropdown.print-menu-opener
|
%button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' }
|
||||||
%button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' }
|
%span.icon.attached
|
||||||
%span.icon.attached
|
%ul#print-pj-menu.print-menu.dropdown-content
|
||||||
%ul#print-pj-menu.print-menu.dropdown-content
|
%li
|
||||||
%li
|
- if dossier.export_and_attachments_downloadable?
|
||||||
- if PiecesJustificativesService.pieces_justificatives_total_size(dossier) < Dossier::TAILLE_MAX_ZIP
|
= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||||
= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
- else
|
||||||
- else
|
%p.menu-item Le téléchargement des pièces jointes est désactivé pour les dossiers de plus de #{number_to_human_size Dossier::TAILLE_MAX_ZIP}.
|
||||||
%p.menu-item Le téléchargement des pièces jointes est désactivé pour les dossiers de plus de #{number_to_human_size Dossier::TAILLE_MAX_ZIP}.
|
|
||||||
|
|
||||||
= render partial: "instructeurs/procedures/dossier_actions",
|
= render partial: "instructeurs/procedures/dossier_actions",
|
||||||
locals: { procedure_id: dossier.procedure.id,
|
locals: { procedure_id: dossier.procedure.id,
|
||||||
|
|
|
@ -99,17 +99,24 @@
|
||||||
%h4 Voir l’attestation
|
%h4 Voir l’attestation
|
||||||
%p Cette attestation a été envoyée automatiquement au demandeur.
|
%p Cette attestation a été envoyée automatiquement au demandeur.
|
||||||
|
|
||||||
%li
|
- if dossier.can_repasser_en_instruction?
|
||||||
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
|
|
||||||
%span.icon.in-progress
|
|
||||||
.dropdown-description
|
|
||||||
%h4 Repasser en instruction
|
|
||||||
L’usager sera notifié que son dossier est réexaminé.
|
|
||||||
- if dossier.termine?
|
|
||||||
%li
|
%li
|
||||||
= link_to supprimer_dossier_instructeur_dossier_path(dossier.procedure, dossier), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier.id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do
|
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
|
||||||
%span.icon.delete
|
%span.icon.in-progress
|
||||||
.dropdown-description
|
.dropdown-description
|
||||||
%h4 Supprimer le dossier
|
%h4 Repasser en instruction
|
||||||
L’usager sera notifié que son dossier est supprimé.
|
L’usager sera notifié que son dossier est réexaminé.
|
||||||
|
- elsif dossier.user_deleted?
|
||||||
|
%li
|
||||||
|
%span.icon.info
|
||||||
|
.dropdown-description
|
||||||
|
%h4 En attente d‘archivage
|
||||||
|
L'usager a supprimé son compte. Vous pouvez archiver puis supprimer le dossier.
|
||||||
|
|
||||||
|
%li
|
||||||
|
= link_to supprimer_dossier_instructeur_dossier_path(dossier.procedure, dossier), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier.id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do
|
||||||
|
%span.icon.delete
|
||||||
|
.dropdown-description
|
||||||
|
%h4 Supprimer le dossier
|
||||||
|
L’usager sera notifié que son dossier est supprimé.
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
|
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
|
||||||
= dossier.id
|
= dossier.id
|
||||||
%td= link_to(dossier.procedure.libelle, dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
|
%td= link_to(dossier.procedure.libelle, dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
|
||||||
%td= link_to(dossier.user.email, dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
|
%td= link_to(dossier.user_email_for(:display), dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
|
||||||
%td.status-col
|
%td.status-col
|
||||||
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
|
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
|
||||||
= status_badge(dossier.state)
|
= status_badge(dossier.state)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddDeletedUserEmailNeverSendToDossiers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :dossiers, :deleted_user_email_never_send, :string
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2021_04_27_124500) do
|
ActiveRecord::Schema.define(version: 2021_04_28_114228) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -274,6 +274,7 @@ ActiveRecord::Schema.define(version: 2021_04_27_124500) do
|
||||||
t.datetime "last_avis_updated_at"
|
t.datetime "last_avis_updated_at"
|
||||||
t.datetime "last_commentaire_updated_at"
|
t.datetime "last_commentaire_updated_at"
|
||||||
t.string "api_entreprise_job_exceptions", array: true
|
t.string "api_entreprise_job_exceptions", array: true
|
||||||
|
t.string "deleted_user_email_never_send"
|
||||||
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
||||||
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
||||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||||
|
|
|
@ -210,7 +210,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'Notification email is sent' do
|
it 'Notification email is sent' do
|
||||||
expect(NotificationMailer).to receive(:send_refused_notification)
|
expect(NotificationMailer).to receive(:send_refuse_notification)
|
||||||
.with(dossier).and_return(NotificationMailer)
|
.with(dossier).and_return(NotificationMailer)
|
||||||
expect(NotificationMailer).to receive(:deliver_later)
|
expect(NotificationMailer).to receive(:deliver_later)
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'Notification email is sent' do
|
it 'Notification email is sent' do
|
||||||
expect(NotificationMailer).to receive(:send_without_continuation_notification)
|
expect(NotificationMailer).to receive(:send_sans_suite_notification)
|
||||||
.with(dossier).and_return(NotificationMailer)
|
.with(dossier).and_return(NotificationMailer)
|
||||||
expect(NotificationMailer).to receive(:deliver_later)
|
expect(NotificationMailer).to receive(:deliver_later)
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
dossier.passer_en_instruction!(instructeur)
|
dossier.passer_en_instruction!(instructeur)
|
||||||
sign_in(instructeur.user)
|
sign_in(instructeur.user)
|
||||||
|
|
||||||
expect(NotificationMailer).to receive(:send_closed_notification)
|
expect(NotificationMailer).to receive(:send_accepte_notification)
|
||||||
.with(dossier)
|
.with(dossier)
|
||||||
.and_return(NotificationMailer)
|
.and_return(NotificationMailer)
|
||||||
|
|
||||||
|
|
|
@ -476,12 +476,12 @@ describe Users::DossiersController, type: :controller do
|
||||||
delivery = double
|
delivery = double
|
||||||
expect(delivery).to receive(:deliver_later).with(no_args)
|
expect(delivery).to receive(:deliver_later).with(no_args)
|
||||||
|
|
||||||
expect(NotificationMailer).to receive(:send_initiated_notification)
|
expect(NotificationMailer).to receive(:send_en_construction_notification)
|
||||||
.and_return(delivery)
|
.and_return(delivery)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
expect(NotificationMailer).not_to receive(:send_en_construction_notification)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
@ -499,7 +499,7 @@ describe Users::DossiersController, type: :controller do
|
||||||
it { expect(flash.alert).to eq(['nop']) }
|
it { expect(flash.alert).to eq(['nop']) }
|
||||||
|
|
||||||
it 'does not send an email' do
|
it 'does not send an email' do
|
||||||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
expect(NotificationMailer).not_to receive(:send_en_construction_notification)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
@ -687,7 +687,7 @@ describe Users::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not send an email' do
|
it 'does not send an email' do
|
||||||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
expect(NotificationMailer).not_to receive(:send_en_construction_notification)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
RSpec.describe NotificationMailer, type: :mailer do
|
RSpec.describe NotificationMailer, type: :mailer do
|
||||||
|
let(:administrateur) { create(:administrateur) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:procedure) { create(:simple_procedure) }
|
let(:procedure) { create(:simple_procedure) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_service, user: user, procedure: procedure) }
|
|
||||||
|
|
||||||
describe '.send_dossier_received' do
|
describe 'send_en_instruction_notification' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_service, user: user, procedure: procedure) }
|
||||||
let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') }
|
let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.procedure.received_mail = email_template
|
dossier.procedure.received_mail = email_template
|
||||||
end
|
end
|
||||||
|
|
||||||
subject(:mail) { described_class.send_dossier_received(dossier) }
|
subject(:mail) { described_class.send_en_instruction_notification(dossier) }
|
||||||
|
|
||||||
it 'creates a commentaire in the messagerie' do
|
it 'creates a commentaire in the messagerie' do
|
||||||
expect { subject.deliver_now }.to change { Commentaire.count }.by(1)
|
expect { subject.deliver_now }.to change { Commentaire.count }.by(1)
|
||||||
|
expect(subject.perform_deliveries).to be_truthy
|
||||||
|
|
||||||
commentaire = Commentaire.last
|
commentaire = Commentaire.last
|
||||||
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
|
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
|
||||||
|
@ -59,4 +61,27 @@ RSpec.describe NotificationMailer, type: :mailer do
|
||||||
expect(subject.from.first).to eq(Mail::Address.new(NO_REPLY_EMAIL).address)
|
expect(subject.from.first).to eq(Mail::Address.new(NO_REPLY_EMAIL).address)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'send_accepte_notification' do
|
||||||
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure: procedure) }
|
||||||
|
let(:email_template) { create(:closed_mail, subject: 'Email subject', body: 'Your dossier was accepted. Thanks.') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
dossier.procedure.closed_mail = email_template
|
||||||
|
end
|
||||||
|
|
||||||
|
subject(:mail) { described_class.send_accepte_notification(dossier) }
|
||||||
|
|
||||||
|
context 'when dossier user is deleted' do
|
||||||
|
before do
|
||||||
|
dossier.user.delete_and_keep_track_dossiers(administrateur)
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not send notification' do
|
||||||
|
expect { subject.deliver_now }.not_to change { Commentaire.count }
|
||||||
|
expect(subject.perform_deliveries).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,23 +1,36 @@
|
||||||
class NotificationMailerPreview < ActionMailer::Preview
|
class NotificationMailerPreview < ActionMailer::Preview
|
||||||
def send_initiated_notification
|
def send_en_construction_notification
|
||||||
p = Procedure.where(id: Mails::InitiatedMail.where("body like ?", "%<img%").pluck(:procedure_id).uniq).order("RANDOM()").first
|
NotificationMailer.send_en_construction_notification(dossier_with_image)
|
||||||
NotificationMailer.send_initiated_notification(p.dossiers.last)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_dossier_received
|
def send_en_instruction_notification
|
||||||
NotificationMailer.send_dossier_received(Dossier.last)
|
NotificationMailer.send_en_instruction_notification(dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_closed_notification
|
def send_accepte_notification
|
||||||
NotificationMailer.send_closed_notification(Dossier.last)
|
NotificationMailer.send_accepte_notification(dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_refused_notification
|
def send_refuse_notification
|
||||||
dossier = Dossier.last.tap { |d| d.assign_attributes(motivation: 'Le montant demandé dépasse le plafond autorisé') }
|
NotificationMailer.send_refuse_notification(dossier_with_motivation)
|
||||||
NotificationMailer.send_refused_notification(dossier)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_without_continuation_notification
|
def send_sans_suite_notification
|
||||||
NotificationMailer.send_without_continuation_notification(Dossier.last)
|
NotificationMailer.send_sans_suite_notification(dossier)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def dossier
|
||||||
|
Dossier.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def dossier_with_image
|
||||||
|
procedure = Procedure.where(id: Mails::InitiatedMail.where("body like ?", "%<img%").pluck(:procedure_id).uniq).order("RANDOM()").first
|
||||||
|
procedure.dossiers.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def dossier_with_motivation
|
||||||
|
Dossier.last.tap { |d| d.assign_attributes(motivation: 'Le montant demandé dépasse le plafond autorisé') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -503,17 +503,17 @@ describe Dossier do
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(NotificationMailer).to receive(:send_dossier_received).and_return(double(deliver_later: nil))
|
allow(NotificationMailer).to receive(:send_en_instruction_notification).and_return(double(deliver_later: nil))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends an email when the dossier becomes en_instruction" do
|
it "sends an email when the dossier becomes en_instruction" do
|
||||||
dossier.passer_en_instruction!(instructeur)
|
dossier.passer_en_instruction!(instructeur)
|
||||||
expect(NotificationMailer).to have_received(:send_dossier_received).with(dossier)
|
expect(NotificationMailer).to have_received(:send_en_instruction_notification).with(dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not an email when the dossier becomes accepte" do
|
it "does not an email when the dossier becomes accepte" do
|
||||||
dossier.accepte!
|
dossier.accepte!
|
||||||
expect(NotificationMailer).to_not have_received(:send_dossier_received)
|
expect(NotificationMailer).to_not have_received(:send_en_instruction_notification)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -926,7 +926,7 @@ describe Dossier do
|
||||||
let(:attestation) { Attestation.new }
|
let(:attestation) { Attestation.new }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true))
|
allow(NotificationMailer).to receive(:send_accepte_notification).and_return(double(deliver_later: true))
|
||||||
allow(dossier).to receive(:build_attestation).and_return(attestation)
|
allow(dossier).to receive(:build_attestation).and_return(attestation)
|
||||||
|
|
||||||
Timecop.freeze(now)
|
Timecop.freeze(now)
|
||||||
|
@ -948,7 +948,7 @@ describe Dossier do
|
||||||
it { expect(operation_serialized['operation']).to eq('accepter') }
|
it { expect(operation_serialized['operation']).to eq('accepter') }
|
||||||
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
|
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
|
||||||
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
|
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
|
||||||
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) }
|
it { expect(NotificationMailer).to have_received(:send_accepte_notification).with(dossier) }
|
||||||
it { expect(dossier.attestation).to eq(attestation) }
|
it { expect(dossier.attestation).to eq(attestation) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -959,7 +959,7 @@ describe Dossier do
|
||||||
let(:attestation) { Attestation.new }
|
let(:attestation) { Attestation.new }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true))
|
allow(NotificationMailer).to receive(:send_accepte_notification).and_return(double(deliver_later: true))
|
||||||
allow(dossier).to receive(:build_attestation).and_return(attestation)
|
allow(dossier).to receive(:build_attestation).and_return(attestation)
|
||||||
|
|
||||||
Timecop.freeze(now)
|
Timecop.freeze(now)
|
||||||
|
@ -975,7 +975,7 @@ describe Dossier do
|
||||||
it { expect(dossier.state).to eq('accepte') }
|
it { expect(dossier.state).to eq('accepte') }
|
||||||
it { expect(last_operation.operation).to eq('accepter') }
|
it { expect(last_operation.operation).to eq('accepter') }
|
||||||
it { expect(last_operation.automatic_operation?).to be_truthy }
|
it { expect(last_operation.automatic_operation?).to be_truthy }
|
||||||
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) }
|
it { expect(NotificationMailer).to have_received(:send_accepte_notification).with(dossier) }
|
||||||
it { expect(dossier.attestation).to eq(attestation) }
|
it { expect(dossier.attestation).to eq(attestation) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1126,30 +1126,26 @@ describe Dossier do
|
||||||
after { Timecop.return }
|
after { Timecop.return }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#attachments_downloadable?' do
|
describe '#export_and_attachments_downloadable?' do
|
||||||
let(:dossier) { create(:dossier, user: user) }
|
let(:dossier) { create(:dossier, user: user) }
|
||||||
# subject { dossier.attachments_downloadable? }
|
|
||||||
|
|
||||||
context "no attachments" do
|
context "no attachments" do
|
||||||
it {
|
it {
|
||||||
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([])
|
expect(dossier.export_and_attachments_downloadable?).to be true
|
||||||
expect(dossier.attachments_downloadable?).to be false
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a small attachment" do
|
context "with a small attachment" do
|
||||||
it {
|
it {
|
||||||
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([Champ.new])
|
|
||||||
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(4.megabytes)
|
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(4.megabytes)
|
||||||
expect(dossier.attachments_downloadable?).to be true
|
expect(dossier.export_and_attachments_downloadable?).to be true
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a too large attachment" do
|
context "with a too large attachment" do
|
||||||
it {
|
it {
|
||||||
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([Champ.new])
|
|
||||||
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(100.megabytes)
|
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(100.megabytes)
|
||||||
expect(dossier.attachments_downloadable?).to be false
|
expect(dossier.export_and_attachments_downloadable?).to be false
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -263,13 +263,16 @@ describe User, type: :model do
|
||||||
|
|
||||||
describe '#can_be_deleted?' do
|
describe '#can_be_deleted?' do
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
let(:administrateur) { create(:administrateur) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
let(:expert) { create(:expert) }
|
||||||
|
|
||||||
subject { user.can_be_deleted? }
|
subject { user.can_be_deleted? }
|
||||||
|
|
||||||
context 'when the user has a dossier in instruction' do
|
context 'when the user has a dossier in instruction' do
|
||||||
let!(:dossier) { create(:dossier, :en_instruction, user: user) }
|
let!(:dossier) { create(:dossier, :en_instruction, user: user) }
|
||||||
|
|
||||||
it { is_expected.to be false }
|
it { is_expected.to be true }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user has no dossier in instruction' do
|
context 'when the user has no dossier in instruction' do
|
||||||
|
@ -278,19 +281,19 @@ describe User, type: :model do
|
||||||
|
|
||||||
context 'when the user is an administrateur' do
|
context 'when the user is an administrateur' do
|
||||||
it 'cannot be deleted' do
|
it 'cannot be deleted' do
|
||||||
administrateur = create(:administrateur)
|
expect(administrateur.user.can_be_deleted?).to be_falsy
|
||||||
user = administrateur.user
|
|
||||||
|
|
||||||
expect(user.can_be_deleted?).to be_falsy
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user is an instructeur' do
|
context 'when the user is an instructeur' do
|
||||||
it 'cannot be deleted' do
|
it 'cannot be deleted' do
|
||||||
instructeur = create(:instructeur)
|
expect(instructeur.user.can_be_deleted?).to be_falsy
|
||||||
user = instructeur.user
|
end
|
||||||
|
end
|
||||||
|
|
||||||
expect(user.can_be_deleted?).to be_falsy
|
context 'when the user is an expert' do
|
||||||
|
it 'cannot be deleted' do
|
||||||
|
expect(expert.user.can_be_deleted?).to be_falsy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -299,14 +302,7 @@ describe User, type: :model do
|
||||||
let(:super_admin) { create(:super_admin) }
|
let(:super_admin) { create(:super_admin) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
context 'with a dossier in instruction' do
|
context 'without a dossier with processing strted' do
|
||||||
let!(:dossier_en_instruction) { create(:dossier, :en_instruction, user: user) }
|
|
||||||
it 'raises' do
|
|
||||||
expect { user.delete_and_keep_track_dossiers(super_admin) }.to raise_error(RuntimeError)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'without a dossier in instruction' do
|
|
||||||
let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) }
|
let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) }
|
||||||
let!(:dossier_brouillon) { create(:dossier, user: user) }
|
let!(:dossier_brouillon) { create(:dossier, user: user) }
|
||||||
|
|
||||||
|
@ -321,28 +317,39 @@ describe User, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a discarded dossier' do
|
context 'with a discarded dossier' do
|
||||||
let!(:dossier_cache) do
|
let(:dossier_to_discard) { create(:dossier, :en_construction, user: user) }
|
||||||
create(:dossier, :en_construction, user: user)
|
let!(:dossier_from_another_user) { create(:dossier, :en_construction, user: create(:user)) }
|
||||||
end
|
|
||||||
let!(:dossier_from_another_user) do
|
|
||||||
create(:dossier, :en_construction, user: create(:user))
|
|
||||||
end
|
|
||||||
|
|
||||||
it "keep track of dossiers and delete user" do
|
it "keep track of dossiers and delete user" do
|
||||||
dossier_cache.discard_and_keep_track!(super_admin, :user_request)
|
dossier_to_discard.discard_and_keep_track!(super_admin, :user_request)
|
||||||
user.delete_and_keep_track_dossiers(super_admin)
|
user.delete_and_keep_track_dossiers(super_admin)
|
||||||
|
|
||||||
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
||||||
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil
|
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil
|
||||||
|
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present
|
||||||
expect(User.find_by(id: user.id)).to be_nil
|
expect(User.find_by(id: user.id)).to be_nil
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "doesn't destroy dossiers of another user" do
|
context 'with dossiers with processing strted' do
|
||||||
dossier_cache.discard_and_keep_track!(super_admin, :user_request)
|
let!(:dossier_en_instruction) { create(:dossier, :en_instruction, user: user) }
|
||||||
user.delete_and_keep_track_dossiers(super_admin)
|
let!(:dossier_termine) { create(:dossier, :accepte, user: user) }
|
||||||
|
|
||||||
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present
|
it "keep track of dossiers and delete user" do
|
||||||
end
|
user.delete_and_keep_track_dossiers(super_admin)
|
||||||
|
|
||||||
|
expect(dossier_en_instruction.reload).to be_present
|
||||||
|
expect(dossier_en_instruction.user).to be_nil
|
||||||
|
expect(dossier_en_instruction.user_email_for(:display)).to eq(user.email)
|
||||||
|
expect { dossier_en_instruction.user_email_for(:notification) }.to raise_error(RuntimeError)
|
||||||
|
|
||||||
|
expect(dossier_termine.reload).to be_present
|
||||||
|
expect(dossier_termine.user).to be_nil
|
||||||
|
expect(dossier_termine.user_email_for(:display)).to eq(user.email)
|
||||||
|
expect { dossier_termine.user_email_for(:notification) }.to raise_error(RuntimeError)
|
||||||
|
|
||||||
|
expect(User.find_by(id: user.id)).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
describe PiecesJustificativesService do
|
describe PiecesJustificativesService do
|
||||||
|
let(:procedure) { create(:procedure, :with_titre_identite) }
|
||||||
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
let(:champ_identite) { dossier.champs.find { |c| c.type == 'Champs::TitreIdentiteChamp' } }
|
||||||
|
let(:bill_signature) do
|
||||||
|
bs = build(:bill_signature, :with_serialized, :with_signature)
|
||||||
|
bs.save(validate: false)
|
||||||
|
bs
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
champ_identite
|
||||||
|
.piece_justificative_file
|
||||||
|
.attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png")
|
||||||
|
create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature)
|
||||||
|
end
|
||||||
|
|
||||||
describe '.liste_pieces_justificatives' do
|
describe '.liste_pieces_justificatives' do
|
||||||
let(:procedure) { create(:procedure, :with_titre_identite) }
|
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
|
||||||
let(:champ_identite) { dossier.champs.find { |c| c.type == 'Champs::TitreIdentiteChamp' } }
|
|
||||||
|
|
||||||
before do
|
|
||||||
champ_identite
|
|
||||||
.piece_justificative_file
|
|
||||||
.attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png")
|
|
||||||
end
|
|
||||||
|
|
||||||
subject { PiecesJustificativesService.liste_pieces_justificatives(dossier) }
|
subject { PiecesJustificativesService.liste_pieces_justificatives(dossier) }
|
||||||
|
|
||||||
# titre identite is too sensitive
|
it "doesn't return sensitive documents like titre_identite" do
|
||||||
# to be exported
|
|
||||||
it 'ensures no titre identite is given' do
|
|
||||||
expect(champ_identite.piece_justificative_file).to be_attached
|
expect(champ_identite.piece_justificative_file).to be_attached
|
||||||
expect(subject.any? { |piece| piece.name == 'piece_justificative_file' }).to be_falsy
|
expect(subject.any? { |piece| piece.name == 'piece_justificative_file' }).to be_falsy
|
||||||
end
|
end
|
||||||
|
@ -22,5 +26,22 @@ describe PiecesJustificativesService do
|
||||||
it "doesn't return export pdf of the dossier" do
|
it "doesn't return export pdf of the dossier" do
|
||||||
expect(subject.any? { |piece| piece.name == 'pdf_export_for_instructeur' }).to be_falsy
|
expect(subject.any? { |piece| piece.name == 'pdf_export_for_instructeur' }).to be_falsy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "doesn't return operation logs of the dossier" do
|
||||||
|
expect(subject.any? { |piece| piece.name == 'serialized' }).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.liste_documents' do
|
||||||
|
subject { PiecesJustificativesService.liste_documents(dossier) }
|
||||||
|
|
||||||
|
it "doesn't return sensitive documents like titre_identite" do
|
||||||
|
expect(champ_identite.piece_justificative_file).to be_attached
|
||||||
|
expect(subject.any? { |piece| piece.name == 'piece_justificative_file' }).to be_falsy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns operation logs of the dossier" do
|
||||||
|
expect(subject.any? { |piece| piece.name == 'serialized' }).to be_truthy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue