commit
0c6cf93376
56 changed files with 1140 additions and 980 deletions
1
Gemfile
1
Gemfile
|
@ -9,6 +9,7 @@ gem 'administrate'
|
|||
gem 'after_party'
|
||||
gem 'anchored'
|
||||
gem 'bcrypt'
|
||||
gem 'bootsnap', '>= 1.4.4', require: false # Reduces boot times through caching; required in config/boot.rb
|
||||
gem 'browser'
|
||||
gem 'chartkick'
|
||||
gem 'chunky_png'
|
||||
|
|
|
@ -134,6 +134,8 @@ GEM
|
|||
bcrypt (3.1.16)
|
||||
bindata (2.4.8)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.7.2)
|
||||
msgpack (~> 1.0)
|
||||
brakeman (5.0.0)
|
||||
browser (5.3.0)
|
||||
builder (3.2.4)
|
||||
|
@ -419,6 +421,7 @@ GEM
|
|||
minitest (5.14.4)
|
||||
momentjs-rails (2.20.1)
|
||||
railties (>= 3.1)
|
||||
msgpack (1.4.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.1.1)
|
||||
mustermann (1.1.1)
|
||||
|
@ -781,6 +784,7 @@ DEPENDENCIES
|
|||
annotate
|
||||
axe-matchers
|
||||
bcrypt
|
||||
bootsnap (>= 1.4.4)
|
||||
brakeman
|
||||
browser
|
||||
capybara
|
||||
|
|
|
@ -20,7 +20,7 @@ class ApplicationController < ActionController::Base
|
|||
before_action :setup_tracking
|
||||
before_action :set_locale
|
||||
|
||||
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur,
|
||||
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur, :current_expert, :expert_signed_in?,
|
||||
:administrateur_signed_in?, :current_administrateur, :current_account
|
||||
|
||||
def staging_authenticate
|
||||
|
@ -32,7 +32,9 @@ class ApplicationController < ActionController::Base
|
|||
def multiple_devise_profile_connect?
|
||||
user_signed_in? && instructeur_signed_in? ||
|
||||
instructeur_signed_in? && administrateur_signed_in? ||
|
||||
user_signed_in? && administrateur_signed_in?
|
||||
instructeur_signed_in? && expert_signed_in? ||
|
||||
user_signed_in? && administrateur_signed_in? ||
|
||||
user_signed_in? && expert_signed_in?
|
||||
end
|
||||
|
||||
def current_instructeur
|
||||
|
@ -51,6 +53,14 @@ class ApplicationController < ActionController::Base
|
|||
current_administrateur.present?
|
||||
end
|
||||
|
||||
def current_expert
|
||||
current_user&.expert
|
||||
end
|
||||
|
||||
def expert_signed_in?
|
||||
current_expert.present?
|
||||
end
|
||||
|
||||
def current_account
|
||||
{
|
||||
administrateur: current_administrateur,
|
||||
|
@ -70,6 +80,8 @@ class ApplicationController < ActionController::Base
|
|||
def authenticate_logged_user!
|
||||
if instructeur_signed_in?
|
||||
authenticate_instructeur!
|
||||
elsif expert_signed_in?
|
||||
authenticate_expert!
|
||||
elsif administrateur_signed_in?
|
||||
authenticate_administrateur!
|
||||
else
|
||||
|
@ -83,6 +95,12 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def authenticate_expert!
|
||||
if !expert_signed_in?
|
||||
redirect_to new_user_session_path
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_administrateur!
|
||||
if !administrateur_signed_in?
|
||||
redirect_to new_user_session_path
|
||||
|
|
|
@ -3,9 +3,8 @@ module CreateAvisConcern
|
|||
|
||||
private
|
||||
|
||||
def create_avis_from_params(dossier, confidentiel = false)
|
||||
def create_avis_from_params(dossier, instructeur_or_expert, confidentiel = false)
|
||||
confidentiel ||= create_avis_params[:confidentiel]
|
||||
|
||||
# Because of a limitation of the email_field rails helper,
|
||||
# the :emails parameter is a 1-element array.
|
||||
# Hence the call to first
|
||||
|
@ -14,7 +13,7 @@ module CreateAvisConcern
|
|||
allowed_dossiers = [dossier]
|
||||
|
||||
if create_avis_params[:invite_linked_dossiers].present?
|
||||
allowed_dossiers += dossier.linked_dossiers_for(current_instructeur)
|
||||
allowed_dossiers += dossier.linked_dossiers_for(instructeur_or_expert)
|
||||
end
|
||||
|
||||
create_results = Avis.create(
|
||||
|
@ -26,8 +25,7 @@ module CreateAvisConcern
|
|||
email: email,
|
||||
introduction: create_avis_params[:introduction],
|
||||
introduction_file: create_avis_params[:introduction_file],
|
||||
claimant: current_instructeur,
|
||||
claimant_type: current_instructeur.dossiers.present? ? 'Instructeur' : 'Expert',
|
||||
claimant: instructeur_or_expert,
|
||||
dossier: dossier,
|
||||
confidentiel: confidentiel,
|
||||
experts_procedure: experts_procedure
|
||||
|
@ -43,10 +41,11 @@ module CreateAvisConcern
|
|||
sent_emails_addresses = []
|
||||
persisted.each do |avis|
|
||||
avis.dossier.demander_un_avis!(avis)
|
||||
|
||||
if avis.dossier == dossier
|
||||
AvisMailer.avis_invitation(avis).deliver_later
|
||||
sent_emails_addresses << avis.email_to_display
|
||||
sent_emails_addresses << avis.expert.email
|
||||
# the email format is already verified, we update value to nil
|
||||
avis.update_column(:email, nil)
|
||||
end
|
||||
end
|
||||
flash.notice = "Une demande d'avis a été envoyée à #{sent_emails_addresses.uniq.join(", ")}"
|
||||
|
|
165
app/controllers/experts/avis_controller.rb
Normal file
165
app/controllers/experts/avis_controller.rb
Normal file
|
@ -0,0 +1,165 @@
|
|||
module Experts
|
||||
class AvisController < ExpertController
|
||||
include CreateAvisConcern
|
||||
|
||||
before_action :authenticate_expert!, except: [:sign_up, :update_expert]
|
||||
before_action :check_if_avis_revoked, only: [:show]
|
||||
before_action :redirect_if_no_sign_up_needed, only: [:sign_up]
|
||||
before_action :set_avis_and_dossier, only: [:show, :instruction, :messagerie, :create_commentaire, :update]
|
||||
|
||||
A_DONNER_STATUS = 'a-donner'
|
||||
DONNES_STATUS = 'donnes'
|
||||
|
||||
def index
|
||||
avis = current_expert.avis.includes(dossier: [groupe_instructeur: :procedure])
|
||||
@avis_by_procedure = avis.to_a.group_by(&:procedure)
|
||||
end
|
||||
|
||||
def procedure
|
||||
@procedure = Procedure.find(params[:procedure_id])
|
||||
expert_avis = current_expert.avis.includes(:dossier).where(dossiers: { groupe_instructeur: GroupeInstructeur.where(procedure: @procedure.id) })
|
||||
@avis_a_donner = expert_avis.without_answer
|
||||
@avis_donnes = expert_avis.with_answer
|
||||
|
||||
@statut = params[:statut].presence || A_DONNER_STATUS
|
||||
|
||||
@avis = case @statut
|
||||
when A_DONNER_STATUS
|
||||
@avis_a_donner
|
||||
when DONNES_STATUS
|
||||
@avis_donnes
|
||||
end
|
||||
|
||||
@avis = @avis.page([params[:page].to_i, 1].max)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def instruction
|
||||
@new_avis = Avis.new
|
||||
end
|
||||
|
||||
def create_avis
|
||||
@procedure = Procedure.find(params[:procedure_id])
|
||||
if !@procedure.feature_enabled?(:expert_not_allowed_to_invite)
|
||||
@new_avis = create_avis_from_params(avis.dossier, current_expert, avis.confidentiel)
|
||||
|
||||
if @new_avis.nil?
|
||||
redirect_to instruction_expert_avis_path(avis.procedure, avis)
|
||||
else
|
||||
set_avis_and_dossier
|
||||
render :instruction
|
||||
end
|
||||
else
|
||||
flash.alert = "Cette démarche ne vous permet pas de demander un avis externe"
|
||||
redirect_to instruction_expert_avis_path(avis.procedure, avis)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @avis.update(avis_params)
|
||||
flash.notice = 'Votre réponse est enregistrée.'
|
||||
@avis.dossier.update!(last_avis_updated_at: Time.zone.now)
|
||||
redirect_to instruction_expert_avis_path(@avis.procedure, @avis)
|
||||
else
|
||||
flash.now.alert = @avis.errors.full_messages
|
||||
@new_avis = Avis.new
|
||||
render :instruction
|
||||
end
|
||||
end
|
||||
|
||||
def sign_up
|
||||
@email = params[:email]
|
||||
@dossier = Avis.includes(:dossier).find(params[:id]).dossier
|
||||
|
||||
render
|
||||
end
|
||||
|
||||
def update_expert
|
||||
procedure_id = params[:procedure_id]
|
||||
avis_id = params[:id]
|
||||
email = params[:email]
|
||||
password = params[:user][:password]
|
||||
|
||||
# Not perfect because the password will not be changed if the user already exists
|
||||
user = User.create_or_promote_to_expert(email, password)
|
||||
|
||||
if user.valid?
|
||||
sign_in(user)
|
||||
|
||||
redirect_to url_for(expert_all_avis_path)
|
||||
else
|
||||
flash[:alert] = user.errors.full_messages
|
||||
redirect_to url_for(sign_up_expert_avis_path(procedure_id, avis_id, email))
|
||||
end
|
||||
end
|
||||
|
||||
def messagerie
|
||||
@commentaire = Commentaire.new
|
||||
end
|
||||
|
||||
def create_commentaire
|
||||
@commentaire = CommentaireService.build(current_expert, avis.dossier, commentaire_params)
|
||||
|
||||
if @commentaire.save
|
||||
@commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||
flash.notice = "Message envoyé"
|
||||
redirect_to messagerie_expert_avis_path(avis.procedure, avis)
|
||||
else
|
||||
flash.alert = @commentaire.errors.full_messages
|
||||
render :messagerie
|
||||
end
|
||||
end
|
||||
|
||||
def bilans_bdf
|
||||
if avis.dossier.etablissement&.entreprise_bilans_bdf.present?
|
||||
extension = params[:format]
|
||||
render extension.to_sym => avis.dossier.etablissement.entreprise_bilans_bdf_to_sheet(extension)
|
||||
else
|
||||
redirect_to instructeur_avis_path(avis)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redirect_if_no_sign_up_needed
|
||||
avis = Avis.find(params[:id])
|
||||
|
||||
if current_expert.present?
|
||||
# an expert is authenticated ... lets see if it can view the dossier
|
||||
|
||||
redirect_to expert_avis_url(avis.procedure, avis)
|
||||
|
||||
elsif avis.expert&.email == params[:email] && avis.expert.user.active?.present?
|
||||
|
||||
redirect_to new_user_session_url
|
||||
end
|
||||
end
|
||||
|
||||
def avis
|
||||
current_expert.avis.includes(dossier: [:avis, :commentaires]).find(params[:id])
|
||||
end
|
||||
|
||||
def check_if_avis_revoked
|
||||
avis = Avis.find(params[:id])
|
||||
if avis.revoked?
|
||||
flash.alert = "Vous n'avez plus accès à ce dossier."
|
||||
redirect_to url_for(root_path)
|
||||
end
|
||||
end
|
||||
|
||||
def set_avis_and_dossier
|
||||
@avis = Avis.find(params[:id])
|
||||
@dossier = @avis.dossier
|
||||
end
|
||||
|
||||
def avis_params
|
||||
params.require(:avis).permit(:answer, :piece_justificative_file)
|
||||
end
|
||||
|
||||
def commentaire_params
|
||||
params.require(:commentaire).permit(:body, :piece_jointe)
|
||||
end
|
||||
end
|
||||
end
|
9
app/controllers/experts/expert_controller.rb
Normal file
9
app/controllers/experts/expert_controller.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module Experts
|
||||
class ExpertController < ApplicationController
|
||||
before_action :authenticate_expert!
|
||||
|
||||
def nav_bar_profile
|
||||
:expert
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,131 +2,14 @@ module Instructeurs
|
|||
class AvisController < InstructeurController
|
||||
include CreateAvisConcern
|
||||
|
||||
before_action :authenticate_instructeur!, except: [:sign_up, :create_instructeur]
|
||||
before_action :check_if_avis_revoked, only: [:show]
|
||||
before_action :redirect_if_no_sign_up_needed, only: [:sign_up]
|
||||
before_action :check_avis_exists_and_email_belongs_to_avis, only: [:sign_up, :create_instructeur]
|
||||
before_action :set_avis_and_dossier, only: [:show, :instruction, :messagerie, :create_commentaire, :update]
|
||||
|
||||
before_action :authenticate_instructeur!
|
||||
A_DONNER_STATUS = 'a-donner'
|
||||
DONNES_STATUS = 'donnes'
|
||||
|
||||
def index
|
||||
avis = current_instructeur.avis.includes(:procedure)
|
||||
@avis_by_procedure = avis.to_a.group_by(&:procedure)
|
||||
end
|
||||
|
||||
def procedure
|
||||
@procedure = Procedure.find(params[:procedure_id])
|
||||
instructeur_avis = current_instructeur.avis.includes(:dossier).where(dossiers: { revision: @procedure.revisions })
|
||||
@avis_a_donner = instructeur_avis.without_answer
|
||||
@avis_donnes = instructeur_avis.with_answer
|
||||
|
||||
@statut = params[:statut].presence || A_DONNER_STATUS
|
||||
|
||||
@avis = case @statut
|
||||
when A_DONNER_STATUS
|
||||
@avis_a_donner
|
||||
when DONNES_STATUS
|
||||
@avis_donnes
|
||||
end
|
||||
|
||||
@avis = @avis.page([params[:page].to_i, 1].max)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def instruction
|
||||
@new_avis = Avis.new
|
||||
end
|
||||
|
||||
def update
|
||||
if @avis.update(avis_params)
|
||||
flash.notice = 'Votre réponse est enregistrée.'
|
||||
@avis.dossier.update!(last_avis_updated_at: Time.zone.now)
|
||||
redirect_to instruction_instructeur_avis_path(@avis.procedure, @avis)
|
||||
else
|
||||
flash.now.alert = @avis.errors.full_messages
|
||||
@new_avis = Avis.new
|
||||
render :instruction
|
||||
end
|
||||
end
|
||||
|
||||
def messagerie
|
||||
@commentaire = Commentaire.new
|
||||
end
|
||||
|
||||
def create_commentaire
|
||||
@commentaire = CommentaireService.build(current_instructeur, avis.dossier, commentaire_params)
|
||||
|
||||
if @commentaire.save
|
||||
@commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||
flash.notice = "Message envoyé"
|
||||
redirect_to messagerie_instructeur_avis_path(avis.procedure, avis)
|
||||
else
|
||||
flash.alert = @commentaire.errors.full_messages
|
||||
render :messagerie
|
||||
end
|
||||
end
|
||||
|
||||
def create_avis
|
||||
@procedure = Procedure.find(params[:procedure_id])
|
||||
if !@procedure.feature_enabled?(:expert_not_allowed_to_invite)
|
||||
@new_avis = create_avis_from_params(avis.dossier, avis.confidentiel)
|
||||
|
||||
if @new_avis.nil?
|
||||
redirect_to instruction_instructeur_avis_path(avis.procedure, avis)
|
||||
else
|
||||
set_avis_and_dossier
|
||||
render :instruction
|
||||
end
|
||||
else
|
||||
flash.alert = "Cette démarche ne vous permet pas de demander un avis externe"
|
||||
redirect_to instruction_instructeur_avis_path(avis.procedure, avis)
|
||||
end
|
||||
end
|
||||
|
||||
def bilans_bdf
|
||||
if avis.dossier.etablissement&.entreprise_bilans_bdf.present?
|
||||
extension = params[:format]
|
||||
render extension.to_sym => avis.dossier.etablissement.entreprise_bilans_bdf_to_sheet(extension)
|
||||
else
|
||||
redirect_to instructeur_avis_path(avis)
|
||||
end
|
||||
end
|
||||
|
||||
def sign_up
|
||||
@email = params[:email]
|
||||
@dossier = Avis.includes(:dossier).find(params[:id]).dossier
|
||||
|
||||
render
|
||||
end
|
||||
|
||||
def create_instructeur
|
||||
procedure_id = params[:procedure_id]
|
||||
avis_id = params[:id]
|
||||
email = params[:email]
|
||||
password = params[:user][:password]
|
||||
|
||||
# Not perfect because the password will not be changed if the user already exists
|
||||
user = User.create_or_promote_to_instructeur(email, password)
|
||||
|
||||
if user.valid?
|
||||
sign_in(user)
|
||||
|
||||
Avis.link_avis_to_instructeur(user.instructeur)
|
||||
redirect_to url_for(instructeur_all_avis_path)
|
||||
else
|
||||
flash[:alert] = user.errors.full_messages
|
||||
redirect_to url_for(sign_up_instructeur_avis_path(procedure_id, avis_id, email))
|
||||
end
|
||||
end
|
||||
|
||||
def revoquer
|
||||
avis = Avis.find(params[:id])
|
||||
if avis.revoke_by!(current_instructeur)
|
||||
flash.notice = "#{avis.email_to_display} ne peut plus donner son avis sur ce dossier."
|
||||
flash.notice = "#{avis.expert.email} ne peut plus donner son avis sur ce dossier."
|
||||
redirect_back(fallback_location: avis_instructeur_dossier_path(avis.procedure, avis.dossier))
|
||||
end
|
||||
end
|
||||
|
@ -136,60 +19,13 @@ module Instructeurs
|
|||
if avis.revivable_by?(current_instructeur)
|
||||
if avis.answer.blank?
|
||||
AvisMailer.avis_invitation(avis).deliver_later
|
||||
flash.notice = "Un mail de relance a été envoyé à #{avis.email_to_display}"
|
||||
flash.notice = "Un mail de relance a été envoyé à #{avis.expert.email}"
|
||||
redirect_back(fallback_location: avis_instructeur_dossier_path(avis.procedure, avis.dossier))
|
||||
else
|
||||
flash.alert = "#{avis.email} a déjà donné son avis"
|
||||
flash.alert = "#{avis.expert.email} a déjà donné son avis"
|
||||
redirect_back(fallback_location: avis_instructeur_dossier_path(avis.procedure, avis.dossier))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_avis_and_dossier
|
||||
@avis = avis
|
||||
@dossier = avis.dossier
|
||||
end
|
||||
|
||||
def redirect_if_no_sign_up_needed
|
||||
avis = Avis.find(params[:id])
|
||||
|
||||
if current_instructeur.present?
|
||||
# a instructeur is authenticated ... lets see if it can view the dossier
|
||||
|
||||
redirect_to instructeur_avis_url(avis.procedure, avis)
|
||||
elsif avis.instructeur&.email == params[:email]
|
||||
# the avis instructeur has already signed up and it sould sign in
|
||||
|
||||
redirect_to new_user_session_url
|
||||
end
|
||||
end
|
||||
|
||||
def check_if_avis_revoked
|
||||
avis = Avis.find(params[:id])
|
||||
if avis.revoked?
|
||||
flash.alert = "Vous n'avez plus accès à ce dossier."
|
||||
redirect_to url_for(root_path)
|
||||
end
|
||||
end
|
||||
|
||||
def check_avis_exists_and_email_belongs_to_avis
|
||||
if !Avis.avis_exists_and_email_belongs_to_avis?(params[:id], params[:email])
|
||||
redirect_to url_for(root_path)
|
||||
end
|
||||
end
|
||||
|
||||
def avis
|
||||
current_instructeur.avis.includes(dossier: [:avis, :commentaires]).find(params[:id])
|
||||
end
|
||||
|
||||
def avis_params
|
||||
params.require(:avis).permit(:answer, :piece_justificative_file)
|
||||
end
|
||||
|
||||
def commentaire_params
|
||||
params.require(:commentaire).permit(:body, :piece_jointe)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,7 +66,7 @@ module Instructeurs
|
|||
@following_instructeurs_emails = dossier.followers_instructeurs.map(&:email)
|
||||
previous_followers = dossier.previous_followers_instructeurs - dossier.followers_instructeurs
|
||||
@previous_following_instructeurs_emails = previous_followers.map(&:email)
|
||||
@avis_emails = dossier.avis.includes(:instructeur).map(&:email_to_display)
|
||||
@avis_emails = dossier.experts.map(&:email)
|
||||
@invites_emails = dossier.invites.map(&:email)
|
||||
@potential_recipients = dossier.groupe_instructeur.instructeurs.reject { |g| g == current_instructeur }
|
||||
end
|
||||
|
@ -181,7 +181,7 @@ module Instructeurs
|
|||
end
|
||||
|
||||
def create_avis
|
||||
@avis = create_avis_from_params(dossier)
|
||||
@avis = create_avis_from_params(dossier, current_instructeur)
|
||||
|
||||
if @avis.nil?
|
||||
redirect_to avis_instructeur_dossier_path(procedure, dossier)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
module Instructeurs
|
||||
class ProceduresController < InstructeurController
|
||||
before_action :ensure_ownership!, except: [:index]
|
||||
before_action :redirect_to_avis_if_needed, only: [:index]
|
||||
|
||||
ITEMS_PER_PAGE = 25
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class API::V2::Schema < GraphQL::Schema
|
|||
Types::DossierType
|
||||
when Commentaire
|
||||
Types::MessageType
|
||||
when Instructeur, User
|
||||
when Instructeur, User, Expert
|
||||
Types::ProfileType
|
||||
when Individual
|
||||
Types::PersonnePhysiqueType
|
||||
|
|
|
@ -12,6 +12,6 @@ module Types
|
|||
]
|
||||
|
||||
field :instructeur, Types::ProfileType, null: false, method: :claimant
|
||||
field :expert, Types::ProfileType, null: true, method: :instructeur
|
||||
field :expert, Types::ProfileType, null: true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,11 +3,6 @@ module DossierLinkHelper
|
|||
if user.is_a?(Instructeur)
|
||||
if user.groupe_instructeurs.include?(dossier.groupe_instructeur)
|
||||
instructeur_dossier_path(dossier.procedure, dossier)
|
||||
else
|
||||
avis = dossier.avis.find_by(instructeur: user)
|
||||
if avis.present?
|
||||
instructeur_avis_path(avis.procedure, avis)
|
||||
end
|
||||
end
|
||||
elsif user.owns_or_invite?(dossier)
|
||||
dossier_path(dossier)
|
||||
|
|
|
@ -6,7 +6,7 @@ class AvisMailer < ApplicationMailer
|
|||
|
||||
def avis_invitation(avis)
|
||||
@avis = avis
|
||||
email = @avis.instructeur&.email || @avis.email
|
||||
email = @avis.expert&.email
|
||||
subject = "Donnez votre avis sur le dossier nº #{@avis.dossier.id} (#{@avis.dossier.procedure.libelle})"
|
||||
|
||||
mail(to: email, subject: subject)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# email :string
|
||||
# introduction :text
|
||||
# revoked_at :datetime
|
||||
# tmp_expert_migrated :boolean default(FALSE)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# claimant_id :integer not null
|
||||
|
@ -23,11 +24,11 @@ class Avis < ApplicationRecord
|
|||
belongs_to :instructeur, optional: true
|
||||
belongs_to :experts_procedure, optional: true
|
||||
belongs_to :claimant, class_name: 'Instructeur', optional: false
|
||||
has_one :procedure, through: :dossier
|
||||
|
||||
has_one_attached :piece_justificative_file
|
||||
has_one_attached :introduction_file
|
||||
has_one :expert, through: :experts_procedure
|
||||
has_one :procedure, through: :experts_procedure
|
||||
|
||||
validates :piece_justificative_file,
|
||||
content_type: AUTHORIZED_CONTENT_TYPES,
|
||||
|
@ -43,7 +44,6 @@ class Avis < ApplicationRecord
|
|||
validates :introduction_file, size: { less_than: 20.megabytes }
|
||||
|
||||
before_validation -> { sanitize_email(:email) }
|
||||
before_create :try_to_assign_instructeur
|
||||
|
||||
default_scope { joins(:dossier) }
|
||||
scope :with_answer, -> { where.not(answer: nil) }
|
||||
|
@ -57,8 +57,29 @@ class Avis < ApplicationRecord
|
|||
attr_accessor :emails
|
||||
attr_accessor :invite_linked_dossiers
|
||||
|
||||
def claimant
|
||||
claimant_id = read_attribute(:claimant_id)
|
||||
claimant_type = read_attribute(:claimant_type)
|
||||
if claimant_type == 'Instructeur' || !tmp_expert_migrated
|
||||
Instructeur.find(claimant_id)
|
||||
else
|
||||
Expert.find(claimant_id)
|
||||
end
|
||||
end
|
||||
|
||||
def claimant=(claimant)
|
||||
self.claimant_id = claimant.id
|
||||
|
||||
if claimant.is_a? Instructeur
|
||||
self.claimant_type = 'Instructeur'
|
||||
else
|
||||
self.claimant_type = 'Expert'
|
||||
self.tmp_expert_migrated = true
|
||||
end
|
||||
end
|
||||
|
||||
def email_to_display
|
||||
instructeur&.email || email
|
||||
expert&.email
|
||||
end
|
||||
|
||||
def self.link_avis_to_instructeur(instructeur)
|
||||
|
@ -77,7 +98,7 @@ class Avis < ApplicationRecord
|
|||
['Créé le', :created_at],
|
||||
['Répondu le', :updated_at],
|
||||
['Instructeur', claimant&.email],
|
||||
['Expert', instructeur&.email]
|
||||
['Expert', expert&.email]
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -102,14 +123,4 @@ class Avis < ApplicationRecord
|
|||
destroy!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def try_to_assign_instructeur
|
||||
instructeur = Instructeur.by_email(email)
|
||||
if instructeur
|
||||
self.instructeur = instructeur
|
||||
self.email = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -94,6 +94,8 @@ class Champ < ApplicationRecord
|
|||
case type_de_champ.type_champ
|
||||
when TypeDeChamp.type_champs.fetch(:carte)
|
||||
geo_areas.blank? || value == '[]'
|
||||
when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||
value.blank? || value == '[]'
|
||||
else
|
||||
value.blank?
|
||||
end
|
||||
|
|
|
@ -74,6 +74,7 @@ class Dossier < ApplicationRecord
|
|||
has_many :followers_instructeurs, through: :follows, source: :instructeur
|
||||
has_many :previous_followers_instructeurs, -> { distinct }, through: :previous_follows, source: :instructeur
|
||||
has_many :avis, inverse_of: :dossier, dependent: :destroy
|
||||
has_many :experts, through: :avis
|
||||
has_many :traitements, -> { order(:processed_at) }, inverse_of: :dossier, dependent: :destroy
|
||||
|
||||
has_many :dossier_operation_logs, -> { order(:created_at) }, inverse_of: :dossier
|
||||
|
@ -475,18 +476,31 @@ class Dossier < ApplicationRecord
|
|||
parts.join
|
||||
end
|
||||
|
||||
def avis_for(instructeur)
|
||||
def avis_for_instructeur(instructeur)
|
||||
if instructeur.dossiers.include?(self)
|
||||
avis.order(created_at: :asc)
|
||||
else
|
||||
avis
|
||||
.where(confidentiel: false)
|
||||
.or(avis.where(claimant: instructeur))
|
||||
.or(avis.where(claimant_id: instructeur.id, claimant_type: 'Instructeur'))
|
||||
.or(avis.where(instructeur: instructeur))
|
||||
.order(created_at: :asc)
|
||||
end
|
||||
end
|
||||
|
||||
def avis_for_expert(expert)
|
||||
if expert.dossiers.include?(self)
|
||||
avis.order(created_at: :asc)
|
||||
else
|
||||
instructeur = expert.user.instructeur.id if expert.user.instructeur
|
||||
avis
|
||||
.where(confidentiel: false)
|
||||
.or(avis.where(claimant_id: expert.id, claimant_type: 'Expert', tmp_expert_migrated: true))
|
||||
.or(avis.where(claimant_id: instructeur, claimant_type: 'Instructeur', tmp_expert_migrated: false))
|
||||
.order(created_at: :asc)
|
||||
end
|
||||
end
|
||||
|
||||
def owner_name
|
||||
if etablissement.present?
|
||||
etablissement.entreprise_raison_sociale
|
||||
|
@ -811,9 +825,9 @@ class Dossier < ApplicationRecord
|
|||
&& PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
|
||||
end
|
||||
|
||||
def linked_dossiers_for(instructeur)
|
||||
def linked_dossiers_for(instructeur_or_expert)
|
||||
dossier_ids = champs.filter(&:dossier_link?).map(&:value).compact
|
||||
(instructeur.dossiers.where(id: dossier_ids) + instructeur.dossiers_from_avis.where(id: dossier_ids)).uniq
|
||||
instructeur_or_expert.dossiers.where(id: dossier_ids)
|
||||
end
|
||||
|
||||
def hash_for_deletion_mail
|
||||
|
|
|
@ -8,8 +8,17 @@
|
|||
#
|
||||
class Expert < ApplicationRecord
|
||||
has_one :user
|
||||
has_many :experts_procedures
|
||||
has_many :avis, through: :experts_procedures
|
||||
has_many :dossiers, through: :avis
|
||||
|
||||
default_scope { eager_load(:user) }
|
||||
|
||||
def email
|
||||
user.email
|
||||
end
|
||||
|
||||
def self.by_email(email)
|
||||
Expert.eager_load(:user).find_by(users: { email: email })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,7 +53,7 @@ class User < ApplicationRecord
|
|||
|
||||
accepts_nested_attributes_for :france_connect_information
|
||||
|
||||
default_scope { eager_load(:instructeur, :administrateur) }
|
||||
default_scope { eager_load(:instructeur, :administrateur, :expert) }
|
||||
|
||||
before_validation -> { sanitize_email(:email) }
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
class AvisSerializer < ActiveModel::Serializer
|
||||
attributes :email,
|
||||
:answer,
|
||||
attributes :answer,
|
||||
:introduction,
|
||||
:created_at,
|
||||
:answered_at
|
||||
|
||||
def email
|
||||
object.email_to_display
|
||||
object.expert.email
|
||||
end
|
||||
|
||||
def created_at
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- content_for(:title, 'Invitation à donner votre avis')
|
||||
- avis_link = @avis.instructeur.present? ? instructeur_avis_url(@avis.procedure, @avis) : sign_up_instructeur_avis_url(@avis.procedure, @avis.id, @avis.email)
|
||||
- avis_link = @avis.expert.user.active?.present? ? expert_avis_url(@avis.procedure, @avis) : sign_up_expert_avis_url(@avis.procedure, @avis.id, @avis.expert.email)
|
||||
|
||||
- content_for(:footer) do
|
||||
Merci de ne pas répondre à cet email. Donnez votre avis
|
||||
|
@ -23,7 +23,7 @@
|
|||
%p{ style: "padding: 8px; color: #333333; background-color: #EEEEEE; font-size: 14px;" }
|
||||
= @avis.introduction
|
||||
|
||||
- if @avis.instructeur.present?
|
||||
- if @avis.expert.user.active?.present?
|
||||
%p
|
||||
= round_button("Donner votre avis", avis_link, :primary)
|
||||
- else
|
||||
|
|
11
app/views/experts/avis/_header.html.haml
Normal file
11
app/views/experts/avis/_header.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
.sub-header
|
||||
.container
|
||||
%ul.breadcrumbs
|
||||
%li= link_to('Avis', expert_all_avis_path)
|
||||
%li= link_to(dossier.procedure.libelle, procedure_expert_avis_index_path(avis.procedure))
|
||||
%li= link_to("Dossier nº #{dossier.id}", expert_avis_path(avis.procedure, avis))
|
||||
|
||||
%ul.tabs
|
||||
= dynamic_tab_item('Demande', expert_avis_path(avis.procedure, avis))
|
||||
= dynamic_tab_item('Avis', instruction_expert_avis_path(avis.procedure, avis), notification: avis.answer.blank?)
|
||||
= dynamic_tab_item('Messagerie', messagerie_expert_avis_path(avis.procedure, avis))
|
41
app/views/experts/avis/index.html.haml
Normal file
41
app/views/experts/avis/index.html.haml
Normal file
|
@ -0,0 +1,41 @@
|
|||
- content_for(:title, "Avis")
|
||||
|
||||
.container
|
||||
%h1.page-title Avis
|
||||
|
||||
%ul.procedure-list
|
||||
- @avis_by_procedure.each do |p, procedure_avis|
|
||||
%li.procedure-item.flex.align-start
|
||||
= link_to(procedure_instructeur_avis_index_path(p)) do
|
||||
.flex
|
||||
|
||||
.procedure-logo{ style: "background-image: url(#{p.logo_url})" }
|
||||
|
||||
.procedure-details
|
||||
%p.procedure-title
|
||||
= procedure_libelle p
|
||||
%ul.procedure-stats.flex
|
||||
%li
|
||||
%object
|
||||
= link_to(procedure_instructeur_avis_index_path(p, statut: Instructeurs::AvisController::A_DONNER_STATUS)) do
|
||||
- without_answer_count = procedure_avis.select { |a| a.answer.nil? }.size
|
||||
- if without_answer_count > 0
|
||||
%span.notifications{ 'aria-label': "notifications" }
|
||||
.stats-number
|
||||
= without_answer_count
|
||||
.stats-legend
|
||||
avis à donner
|
||||
%li
|
||||
%object
|
||||
= link_to(procedure_instructeur_avis_index_path(p, statut: Instructeurs::AvisController::DONNES_STATUS)) do
|
||||
- with_answer_count = procedure_avis.select { |a| a.answer.present? }.size
|
||||
.stats-number= with_answer_count
|
||||
.stats-legend
|
||||
= pluralize(with_answer_count, "avis donné")
|
||||
|
||||
- if p.close?
|
||||
.procedure-status
|
||||
%span.label Close
|
||||
- elsif p.depubliee?
|
||||
.procedure-status
|
||||
%span.label Dépubliée
|
38
app/views/experts/avis/instruction.html.haml
Normal file
38
app/views/experts/avis/instruction.html.haml
Normal file
|
@ -0,0 +1,38 @@
|
|||
- content_for(:title, "Avis · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
|
||||
|
||||
.container
|
||||
%section.give-avis
|
||||
%h1.tab-title Donner votre avis
|
||||
%h2.claimant
|
||||
Demandeur :
|
||||
%span.email= @avis.claimant.email
|
||||
%span.date Demande d'avis envoyée le #{l(@avis.created_at, format: '%d/%m/%y')}
|
||||
%p.introduction= @avis.introduction
|
||||
|
||||
- if @avis.introduction_file.attached?
|
||||
= render partial: 'shared/attachment/show', locals: { attachment: @avis.introduction_file.attachment }
|
||||
%br/
|
||||
|
||||
= form_for @avis, url: expert_avis_path(@avis.procedure, @avis), html: { class: 'form' } do |f|
|
||||
= f.text_area :answer, rows: 3, placeholder: 'Votre avis', required: true
|
||||
= text_upload_and_render f, @avis.piece_justificative_file
|
||||
|
||||
.flex.justify-between.align-baseline
|
||||
%p.confidentiel.flex
|
||||
- if @avis.confidentiel?
|
||||
%span.icon.lock
|
||||
%span
|
||||
Cet avis est confidentiel et n'est pas affiché aux autres experts consultés
|
||||
- else
|
||||
%span
|
||||
Cet avis est partagé avec les autres experts
|
||||
.send-wrapper
|
||||
= f.submit 'Envoyer votre avis', class: 'button send'
|
||||
|
||||
- if !@dossier.termine? && !@avis.procedure.feature_enabled?(:expert_not_allowed_to_invite)
|
||||
= render partial: "experts/shared/avis/form", locals: { url: avis_expert_avis_path(@avis.procedure, @avis), linked_dossiers: @dossier.linked_dossiers_for(current_expert), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
|
||||
|
||||
- if @dossier.avis_for_expert(current_expert).present?
|
||||
= render partial: 'experts/shared/avis/list', locals: { avis: @dossier.avis_for_expert(current_expert), avis_seen_at: nil }
|
5
app/views/experts/avis/messagerie.html.haml
Normal file
5
app/views/experts/avis/messagerie.html.haml
Normal file
|
@ -0,0 +1,5 @@
|
|||
- content_for(:title, "Messagerie · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
|
||||
|
||||
= render partial: "shared/dossiers/messagerie", locals: { dossier: @dossier, connected_user: current_expert, messagerie_seen_at: nil, new_commentaire: @commentaire, form_url: commentaire_expert_avis_path(@avis) }
|
45
app/views/experts/avis/procedure.html.haml
Normal file
45
app/views/experts/avis/procedure.html.haml
Normal file
|
@ -0,0 +1,45 @@
|
|||
- avis_statut = (@statut == Experts::AvisController::A_DONNER_STATUS) ? 'à donner' : 'rendus'
|
||||
- content_for(:title, "Avis #{avis_statut}")
|
||||
|
||||
#procedure-show
|
||||
.sub-header
|
||||
.container.flex
|
||||
|
||||
.procedure-logo{ style: "background-image: url(#{@procedure.logo_url})",
|
||||
role: 'img', 'aria-label': "logo de la démarche #{@procedure.libelle}" }
|
||||
|
||||
.procedure-header
|
||||
%h1= procedure_libelle @procedure
|
||||
|
||||
%ul.tabs
|
||||
= tab_item('avis à donner',
|
||||
procedure_expert_avis_index_path(statut: Instructeurs::AvisController::A_DONNER_STATUS),
|
||||
active: @statut == Instructeurs::AvisController::A_DONNER_STATUS,
|
||||
badge: @avis_a_donner.count,
|
||||
notification: @avis_a_donner.any?)
|
||||
|
||||
= tab_item("avis #{'donné'.pluralize(@avis_donnes.count)}",
|
||||
procedure_expert_avis_index_path(statut: Instructeurs::AvisController::DONNES_STATUS),
|
||||
active: @statut == Instructeurs::AvisController::DONNES_STATUS,
|
||||
badge: @avis_donnes.count)
|
||||
|
||||
.container
|
||||
- if @avis.present?
|
||||
%table.table.dossiers-table.hoverable
|
||||
%thead
|
||||
%tr
|
||||
%th.number-col Nº dossier
|
||||
%th Demandeur
|
||||
%th Démarche
|
||||
%tbody
|
||||
- @avis.each do |avis|
|
||||
%tr
|
||||
%td.number-col
|
||||
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
|
||||
%span.icon.folder
|
||||
#{avis.dossier.id}
|
||||
%td= link_to(avis.dossier.user.email, 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)
|
||||
- else
|
||||
%h2.empty-text Aucun avis
|
30
app/views/experts/avis/shared/avis/_form.html.haml
Normal file
30
app/views/experts/avis/shared/avis/_form.html.haml
Normal file
|
@ -0,0 +1,30 @@
|
|||
%section.ask-avis
|
||||
%h1.tab-title Inviter des personnes à donner leur avis
|
||||
%p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier.
|
||||
|
||||
= form_for avis, url: url, html: { class: 'form' } do |f|
|
||||
= f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);"
|
||||
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
|
||||
%p.tab-title Ajouter une pièce jointe
|
||||
.form-group
|
||||
= text_upload_and_render f, avis.introduction_file
|
||||
|
||||
- if linked_dossiers.present?
|
||||
= f.check_box :invite_linked_dossiers, {}, true, false
|
||||
= f.label :invite_linked_dossiers, t('helpers.label.invite_linked_dossiers', count: linked_dossiers.length, ids: linked_dossiers.map(&:id).to_sentence)
|
||||
|
||||
.flex.justify-between.align-baseline
|
||||
- if must_be_confidentiel
|
||||
%p.confidentiel.flex
|
||||
%span.icon.lock
|
||||
%span
|
||||
Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
|
||||
|
||||
- else
|
||||
.confidentiel-wrapper
|
||||
= f.label :confidentiel, 'Cet avis sera '
|
||||
= f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);"
|
||||
.confidentiel-explanation.hidden
|
||||
Il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
|
||||
|
||||
= f.submit 'Demander un avis', class: 'button primary send'
|
5
app/views/experts/avis/show.html.haml
Normal file
5
app/views/experts/avis/show.html.haml
Normal file
|
@ -0,0 +1,5 @@
|
|||
- content_for(:title, "Demande · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
|
||||
|
||||
= render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'expert' }
|
|
@ -4,7 +4,7 @@
|
|||
%p.description= @dossier.procedure.libelle
|
||||
%p.dossier Dossier nº #{@dossier.id}
|
||||
.column
|
||||
= form_for(User.new, url: { controller: "instructeurs/avis", action: :create_instructeur }, method: :post, html: { class: "form" }) do |f|
|
||||
= form_for(User.new, url: { controller: "experts/avis", action: :update_expert }, method: :post, html: { class: "form" }) do |f|
|
||||
%h1 Créez-vous un compte
|
||||
|
||||
= f.label :email, "Email"
|
30
app/views/experts/shared/avis/_form.html.haml
Normal file
30
app/views/experts/shared/avis/_form.html.haml
Normal file
|
@ -0,0 +1,30 @@
|
|||
%section.ask-avis
|
||||
%h1.tab-title Inviter des personnes à donner leur avis
|
||||
%p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier.
|
||||
|
||||
= form_for avis, url: url, html: { class: 'form' } do |f|
|
||||
= f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);"
|
||||
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
|
||||
%p.tab-title Ajouter une pièce jointe
|
||||
.form-group
|
||||
= text_upload_and_render f, avis.introduction_file
|
||||
|
||||
- if linked_dossiers.present?
|
||||
= f.check_box :invite_linked_dossiers, {}, true, false
|
||||
= f.label :invite_linked_dossiers, t('helpers.label.invite_linked_dossiers', count: linked_dossiers.length, ids: linked_dossiers.map(&:id).to_sentence)
|
||||
|
||||
.flex.justify-between.align-baseline
|
||||
- if must_be_confidentiel
|
||||
%p.confidentiel.flex
|
||||
%span.icon.lock
|
||||
%span
|
||||
Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
|
||||
|
||||
- else
|
||||
.confidentiel-wrapper
|
||||
= f.label :confidentiel, 'Cet avis sera '
|
||||
= f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);"
|
||||
.confidentiel-explanation.hidden
|
||||
Il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
|
||||
|
||||
= f.submit 'Demander un avis', class: 'button primary send'
|
38
app/views/experts/shared/avis/_list.html.haml
Normal file
38
app/views/experts/shared/avis/_list.html.haml
Normal file
|
@ -0,0 +1,38 @@
|
|||
%section.list-avis
|
||||
%h1.tab-title
|
||||
Avis des invités
|
||||
%span.count= avis.count
|
||||
|
||||
%ul
|
||||
- avis.each do |avis|
|
||||
%li.one-avis.flex.align-start
|
||||
.width-100
|
||||
%h2.claimant
|
||||
= "#{t('claimant', scope: 'activerecord.attributes.avis')} :"
|
||||
%span.email= (avis.claimant.email == current_expert.email) ? 'Vous' : avis.claimant.email
|
||||
- if avis.confidentiel?
|
||||
%span.confidentiel
|
||||
= t('confidentiel', scope: 'activerecord.attributes.avis')
|
||||
%span.icon.lock{ title: t('confidentiel', scope: 'helpers.hint') }
|
||||
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.created_at) }
|
||||
= t('demande_envoyee_le', scope: 'views.shared.avis', date: l(avis.created_at, format: '%d/%m/%y à %H:%M'))
|
||||
%p= avis.introduction
|
||||
|
||||
.answer.flex.align-start
|
||||
%span.icon.bubble.avis-icon
|
||||
.width-100
|
||||
%h2.instructeur
|
||||
= (avis.expert.email == current_expert.email) ? 'Vous' : avis.expert.email
|
||||
- if avis.answer.present?
|
||||
- if avis.revoked?
|
||||
%span.waiting{ class: highlight_if_unseen_class(avis_seen_at, avis.revoked_at) }
|
||||
= t('demande_revoquee_le', scope: 'views.shared.avis', date: l(avis.revoked_at, format: '%d/%m/%y à %H:%M'))
|
||||
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.updated_at) }
|
||||
= t('reponse_donnee_le', scope: 'views.shared.avis', date: l(avis.updated_at, format: '%d/%m/%y à %H:%M'))
|
||||
- else
|
||||
%span.waiting
|
||||
= t('en_attente', scope: 'views.shared.avis')
|
||||
- if avis.piece_justificative_file.attached?
|
||||
= render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
|
||||
.answer-body
|
||||
= simple_format(avis.answer)
|
|
@ -22,24 +22,24 @@
|
|||
%span.icon.bubble.avis-icon
|
||||
.width-100
|
||||
%h2.instructeur
|
||||
= (avis.email_to_display == current_instructeur.email) ? 'Vous' : avis.email_to_display
|
||||
= (avis.expert.email == current_instructeur.email) ? 'Vous' : avis.expert.email
|
||||
- if avis.answer.present?
|
||||
- if avis.revoked?
|
||||
%span.waiting{ class: highlight_if_unseen_class(avis_seen_at, avis.revoked_at) }
|
||||
= t('demande_revoquee_le', scope: 'views.shared.avis', date: l(avis.revoked_at, format: '%d/%m/%y à %H:%M'))
|
||||
- else
|
||||
- if avis.revokable_by?(current_instructeur)
|
||||
%span.waiting= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.email_to_display) }, method: :patch)
|
||||
%span.waiting= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.expert.email) }, method: :patch)
|
||||
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.updated_at) }
|
||||
= t('reponse_donnee_le', scope: 'views.shared.avis', date: l(avis.updated_at, format: '%d/%m/%y à %H:%M'))
|
||||
- else
|
||||
%span.waiting
|
||||
= t('en_attente', scope: 'views.shared.avis')
|
||||
|
|
||||
%span.waiting= link_to(t('revive', scope: 'helpers.label'), revive_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revive', scope: 'helpers.confirmation', email: avis.email_to_display) })
|
||||
%span.waiting= link_to(t('revive', scope: 'helpers.label'), revive_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revive', scope: 'helpers.confirmation', email: avis.expert.email) })
|
||||
- if avis.revokable_by?(current_instructeur)
|
||||
|
|
||||
= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.email_to_display) }, method: :patch)
|
||||
= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.expert.email) }, method: :patch)
|
||||
- if avis.piece_justificative_file.attached?
|
||||
= render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
|
||||
.answer-body
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
= link_to instructeur_procedures_path, class: "menu-item menu-link" do
|
||||
= image_tag "icons/switch-profile.svg", alt: ''
|
||||
= t('go_instructor', scope: [:layouts])
|
||||
- if expert_signed_in? && nav_bar_profile != :expert
|
||||
%li
|
||||
= link_to expert_all_avis_path, class: "menu-item menu-link" do
|
||||
= image_tag "icons/switch-profile.svg", alt: ''
|
||||
= t('go_expert', scope: [:layouts])
|
||||
- if administrateur_signed_in? && nav_bar_profile != :administrateur
|
||||
%li
|
||||
= link_to admin_procedures_path, class: "menu-item menu-link" do
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
|
||||
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
||||
require "bundler/setup" # Set up gems listed in the Gemfile.
|
||||
require "bootsnap/setup" # Speed up boot time by caching expensive operations.
|
||||
|
|
|
@ -3,6 +3,7 @@ en:
|
|||
go_superadmin: "Switch to super-admin"
|
||||
go_user: "Switch to user"
|
||||
go_instructor: "Switch to instructor"
|
||||
go_expert: "Switch to expert"
|
||||
go_admin: "Switch to administrator"
|
||||
profile: "See my profile"
|
||||
logout: "Log out"
|
||||
|
|
|
@ -3,6 +3,7 @@ fr:
|
|||
go_superadmin: "Passer en super-admin"
|
||||
go_user: "Passer en usager"
|
||||
go_instructor: "Passer en instructeur"
|
||||
go_expert: "Passer en expert"
|
||||
go_admin: "Passer en administrateur"
|
||||
profile: "Voir mon profil"
|
||||
logout: "Se déconnecter"
|
||||
|
|
|
@ -285,6 +285,36 @@ Rails.application.routes.draw do
|
|||
patch 'update_email' => 'profil#update_email'
|
||||
end
|
||||
|
||||
#
|
||||
# Expert
|
||||
#
|
||||
scope module: 'experts', as: 'expert' do
|
||||
get 'avis', to: 'avis#index', as: 'all_avis'
|
||||
|
||||
# this redirections are ephemeral, to ensure that emails sent to experts before are still valid
|
||||
# TODO : they will be removed in September, 2020
|
||||
get 'avis/:id', to: redirect('/procedures/old/avis/%{id}')
|
||||
get 'avis/:id/sign_up/email/:email', to: redirect("/procedures/old/avis/%{id}/sign_up/email/%{email}"), constraints: { email: /.*/ }
|
||||
|
||||
resources :procedures, only: [], param: :procedure_id do
|
||||
member do
|
||||
resources :avis, only: [:show, :update] do
|
||||
get '', action: 'procedure', on: :collection, as: :procedure
|
||||
member do
|
||||
get 'instruction'
|
||||
get 'messagerie'
|
||||
post 'commentaire' => 'avis#create_commentaire'
|
||||
post 'avis' => 'avis#create_avis'
|
||||
get 'bilans_bdf'
|
||||
|
||||
get 'sign_up/email/:email' => 'avis#sign_up', constraints: { email: /.*/ }, as: 'sign_up'
|
||||
post 'sign_up/email/:email' => 'avis#update_expert', constraints: { email: /.*/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Instructeur
|
||||
#
|
||||
|
@ -309,16 +339,12 @@ Rails.application.routes.draw do
|
|||
resources :avis, only: [:show, :update] do
|
||||
get '', action: 'procedure', on: :collection, as: :procedure
|
||||
member do
|
||||
get 'instruction'
|
||||
get 'messagerie'
|
||||
post 'commentaire' => 'avis#create_commentaire'
|
||||
post 'avis' => 'avis#create_avis'
|
||||
patch 'revoquer'
|
||||
get 'revive'
|
||||
get 'bilans_bdf'
|
||||
|
||||
get 'sign_up/email/:email' => 'avis#sign_up', constraints: { email: /.*/ }, as: 'sign_up'
|
||||
post 'sign_up/email/:email' => 'avis#create_instructeur', constraints: { email: /.*/ }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddTmpExpertMigratedToAvis < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :avis, :tmp_expert_migrated, :boolean, default: false
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_03_07_143807) do
|
||||
ActiveRecord::Schema.define(version: 2021_03_11_141956) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -123,6 +123,7 @@ ActiveRecord::Schema.define(version: 2021_03_07_143807) do
|
|||
t.datetime "revoked_at"
|
||||
t.bigint "experts_procedure_id"
|
||||
t.string "claimant_type"
|
||||
t.boolean "tmp_expert_migrated", default: false
|
||||
t.index ["claimant_id"], name: "index_avis_on_claimant_id"
|
||||
t.index ["dossier_id"], name: "index_avis_on_dossier_id"
|
||||
t.index ["experts_procedure_id"], name: "index_avis_on_experts_procedure_id"
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
module Mailers
|
||||
class AttestationClosedMailDiscrepancyMailer < ApplicationMailer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def missing_attestation_tag_email(admin, procedures)
|
||||
procedures = procedures.sort_by(&:id)
|
||||
mail(to: admin.email, subject: subject(procedures), body: body(procedures))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def subject(procedures)
|
||||
if procedures.count == 1
|
||||
procedure_ids = "votre démarche nº #{procedures.first.id}"
|
||||
else
|
||||
procedure_ids = 'vos démarches nº ' + procedures.map(&:id).join(', ')
|
||||
end
|
||||
"#{APPLICATION_NAME} – mise à jour nécessaire de l’accusé d’acceptation de #{procedure_ids}"
|
||||
end
|
||||
|
||||
def body(procedures)
|
||||
<<~HEREDOC
|
||||
Bonjour,
|
||||
|
||||
Pour des raisons de confidentialité, le mode de transmission des attestations aux usagers évolue.
|
||||
|
||||
À compter du 30 avril, les mails d’accusé d’acceptation émis par #{APPLICATION_NAME} ne
|
||||
comporteront plus d’attestation en pièce jointe comme c’est le cas aujourd’hui.
|
||||
|
||||
À la place, le mail contiendra un lien permettant à l’usager de télécharger son
|
||||
attestation dirctement dans son espace sécurisé sur #{APPLICATION_NAME}.
|
||||
|
||||
Ce lien de téléchargement est généré par la balise --lien attestation--.
|
||||
|
||||
#{detail_procedures(procedures)}
|
||||
|
||||
Pour toute question vous pouvez nous joindre par téléphone au #{CONTACT_PHONE}
|
||||
ou sur l’adresse email #{CONTACT_EMAIL}.
|
||||
-- \nL’équipe #{APPLICATION_NAME}
|
||||
HEREDOC
|
||||
end
|
||||
|
||||
def detail_procedures(procedures)
|
||||
if procedures.count == 1
|
||||
p = procedures.first
|
||||
|
||||
<<~HEREDOC.chomp
|
||||
Vous êtes administrateur de la démarche suivante :
|
||||
#{p.libelle} (nº #{p.id})
|
||||
|
||||
Cette démarche donne lieu à l’émission d’une attestation, et son accusé
|
||||
d’acceptation a été personnalisé. Pour respecter la rédaction de votre accusé
|
||||
d’acceptation, nous ne prendrons pas l’initiative d’y ajouter la balise --lien attestation--.
|
||||
|
||||
Afin que vos usagers puissent continuer à accéder facilement à leurs attestations
|
||||
dans leurs démarches futures, nous vous invitons à ajouter à votre convenance la
|
||||
balise --lien attestation-- dans votre accusé d’acceptation. Vous pouvez le faire en
|
||||
cliquant sur le lien suivant :
|
||||
|
||||
#{edit_admin_procedure_mail_template_url(p, Mails::ClosedMail::SLUG)}
|
||||
HEREDOC
|
||||
else
|
||||
liste_procedures = procedures.map { |p| "- #{p.libelle} (nº #{p.id}) – #{edit_admin_procedure_mail_template_url(p, Mails::ClosedMail::SLUG)}" }.join("\n")
|
||||
|
||||
<<~HEREDOC.chomp
|
||||
Vous êtes administrateur sur plusieurs démarches qui donnent lieu à l’émission
|
||||
d’une attestation, et dont l’accusé d’acceptation a été personnalisé. Pour respecter
|
||||
la rédaction de vos accusés d’acceptation, nous ne prendrons pas l’initiative d’y
|
||||
ajouter de balise --lien attestation--.
|
||||
|
||||
Afin que vos usagers puissent continuer à accéder facilement à leurs attestations
|
||||
dans leurs démarches futures, nous vous invitons à ajouter à votre convenance la
|
||||
balise --lien attestation-- dans vos accusés d’acceptation.
|
||||
|
||||
Vous trouverez ci-après la liste des démarches concernées, ainsi que les liens vous
|
||||
permettant d’éditer les accusés d’acceptation correspondants.
|
||||
|
||||
#{liste_procedures}
|
||||
HEREDOC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: backfill_claimant_id_for_experts_on_avis_table'
|
||||
task backfill_claimant_id_for_experts_on_avis_table: :environment do
|
||||
puts "Running deploy task 'backfill_claimant_id_for_experts_on_avis_table'"
|
||||
|
||||
avis_experts_claimant = Avis.where(claimant_type: 'Expert', tmp_expert_migrated: false)
|
||||
progress = ProgressReport.new(avis_experts_claimant.count)
|
||||
|
||||
avis_experts_claimant.find_each do |avis|
|
||||
claimant_instructeur = Instructeur.find(avis.claimant_id)
|
||||
if claimant_instructeur.user
|
||||
claimant_expert = claimant_instructeur.user.expert
|
||||
if !claimant_expert
|
||||
User.create_or_promote_to_expert(claimant_instructeur.user.email, SecureRandom.hex)
|
||||
claimant_expert = claimant_instructeur.reload.user.expert
|
||||
ExpertsProcedure.find_or_create_by(procedure: avis.procedure, expert: claimant_expert)
|
||||
end
|
||||
avis.update_columns(claimant_id: claimant_expert.id, tmp_expert_migrated: true)
|
||||
else
|
||||
# Avis associated to an Instructeur with no user are bad data: delete it
|
||||
avis.destroy!
|
||||
end
|
||||
progress.inc
|
||||
end
|
||||
progress.finish
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
354
spec/controllers/experts/avis_controller_spec.rb
Normal file
354
spec/controllers/experts/avis_controller_spec.rb
Normal file
|
@ -0,0 +1,354 @@
|
|||
describe Experts::AvisController, type: :controller do
|
||||
context 'with an expert signed in' do
|
||||
render_views
|
||||
|
||||
let(:now) { Time.zone.parse('01/02/2345') }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:claimant) { create(:expert) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let(:another_procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let!(:avis_without_answer) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure) }
|
||||
let!(:avis_with_answer) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, answer: 'yop') }
|
||||
|
||||
before do
|
||||
sign_in(expert.user)
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get :index }
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis_by_procedure).flatten).to include(procedure) }
|
||||
it { expect(assigns(:avis_by_procedure).flatten).not_to include(another_procedure) }
|
||||
end
|
||||
|
||||
describe '#procedure' do
|
||||
before { get :procedure, params: { procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis_a_donner)).to match([avis_without_answer]) }
|
||||
it { expect(assigns(:avis_donnes)).to match([avis_with_answer]) }
|
||||
it { expect(assigns(:statut)).to eq('a-donner') }
|
||||
|
||||
context 'with a statut equal to donnes' do
|
||||
before { get :procedure, params: { statut: 'donnes', procedure_id: procedure.id } }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('donnes') }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#bilans_bdf' do
|
||||
before { get :bilans_bdf, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to redirect_to(instructeur_avis_path(avis_without_answer)) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
subject { get :show, params: { id: avis_with_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
context 'with a valid avis' do
|
||||
before { subject }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_with_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
context 'with a revoked avis' do
|
||||
it "refuse l'accès au dossier" do
|
||||
avis_with_answer.update!(revoked_at: Time.zone.now)
|
||||
subject
|
||||
expect(flash.alert).to eq("Vous n'avez plus accès à ce dossier.")
|
||||
expect(response).to redirect_to(root_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#instruction' do
|
||||
before { get :instruction, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
describe '#messagerie' do
|
||||
before { get :messagerie, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
context 'without attachment' do
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
patch :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer' } }
|
||||
avis_without_answer.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
it 'should be ok' do
|
||||
expect(response).to redirect_to(instruction_expert_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(avis_without_answer.answer).to eq('answer')
|
||||
expect(avis_without_answer.piece_justificative_file).to_not be_attached
|
||||
expect(dossier.reload.last_avis_updated_at).to eq(now)
|
||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with attachment' do
|
||||
include ActiveJob::TestHelper
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
|
||||
before do
|
||||
expect(ClamavService).to receive(:safe_file?).and_return(true)
|
||||
post :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer', piece_justificative_file: file } }
|
||||
perform_enqueued_jobs
|
||||
avis_without_answer.reload
|
||||
end
|
||||
|
||||
it 'should be ok' do
|
||||
expect(response).to redirect_to(instruction_expert_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(avis_without_answer.answer).to eq('answer')
|
||||
expect(avis_without_answer.piece_justificative_file).to be_attached
|
||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_commentaire' do
|
||||
let(:file) { nil }
|
||||
let(:scan_result) { true }
|
||||
let(:now) { Time.zone.parse("14/07/1789") }
|
||||
|
||||
subject { post :create_commentaire, params: { id: avis_without_answer.id, procedure_id: procedure.id, commentaire: { body: 'commentaire body', piece_jointe: file } } }
|
||||
|
||||
before do
|
||||
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
|
||||
Timecop.freeze(now)
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
it do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to(messagerie_expert_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(dossier.commentaires.map(&:body)).to match(['commentaire body'])
|
||||
expect(dossier.reload.last_commentaire_updated_at).to eq(now)
|
||||
end
|
||||
|
||||
context "with a file" do
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
|
||||
it do
|
||||
subject
|
||||
expect(Commentaire.last.piece_jointe.filename).to eq("piece_justificative_0.pdf")
|
||||
end
|
||||
|
||||
it { expect { subject }.to change(Commentaire, :count).by(1) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#expert_cannot_invite_another_expert' do
|
||||
let!(:previous_avis) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, confidentiel: previous_avis_confidentiel) }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:intro) { 'introduction' }
|
||||
let(:emails) { ["toto@totomail.com"] }
|
||||
let(:invite_linked_dossiers) { nil }
|
||||
|
||||
before do
|
||||
Flipper.enable_actor(:expert_not_allowed_to_invite, procedure)
|
||||
post :create_avis, params: { id: previous_avis.id, procedure_id: procedure.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers, introduction_file: @introduction_file } }
|
||||
end
|
||||
|
||||
context 'when the expert cannot invite another expert' do
|
||||
let(:asked_confidentiel) { false }
|
||||
it { expect(flash.alert).to eq("Cette démarche ne vous permet pas de demander un avis externe") }
|
||||
it { expect(response).to redirect_to(instruction_expert_avis_path(procedure, previous_avis)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_avis' do
|
||||
let!(:previous_avis) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, confidentiel: previous_avis_confidentiel) }
|
||||
let(:emails) { ['a@b.com'] }
|
||||
let(:intro) { 'introduction' }
|
||||
let(:created_avis) { Avis.last }
|
||||
let!(:old_avis_count) { Avis.count }
|
||||
let(:invite_linked_dossiers) { nil }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
@introduction_file = fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf')
|
||||
post :create_avis, params: { id: previous_avis.id, procedure_id: procedure.id, avis: { emails: emails, introduction: intro, experts_procedure: experts_procedure, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers, introduction_file: @introduction_file } }
|
||||
created_avis.reload
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
context 'when an invalid email' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:emails) { ["toto.fr"] }
|
||||
|
||||
it { expect(response).to render_template :instruction }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(Avis.last).to eq(previous_avis) }
|
||||
it { expect(dossier.last_avis_updated_at).to eq(nil) }
|
||||
end
|
||||
|
||||
context 'ask review with attachment' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:emails) { ["toto@totomail.com"] }
|
||||
|
||||
it { expect(created_avis.introduction_file).to be_attached }
|
||||
it { expect(created_avis.introduction_file.filename).to eq("piece_justificative_0.pdf") }
|
||||
it { expect(created_avis.dossier.reload.last_avis_updated_at).to eq(now) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à toto@totomail.com") }
|
||||
end
|
||||
|
||||
context 'with multiple emails' do
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:emails) { ["toto.fr,titi@titimail.com"] }
|
||||
|
||||
it { expect(response).to render_template :instruction }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à titi@titimail.com") }
|
||||
it { expect(Avis.count).to eq(old_avis_count + 1) }
|
||||
end
|
||||
|
||||
context 'when the previous avis is public' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
|
||||
context 'when the user asked for a public avis' do
|
||||
let(:asked_confidentiel) { false }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(false) }
|
||||
it { expect(created_avis.introduction).to eq(intro) }
|
||||
it { expect(created_avis.dossier).to eq(previous_avis.dossier) }
|
||||
it { expect(created_avis.claimant).to eq(expert) }
|
||||
it { expect(response).to redirect_to(instruction_expert_avis_path(previous_avis.procedure, previous_avis)) }
|
||||
end
|
||||
|
||||
context 'when the user asked for a confidentiel avis' do
|
||||
let(:asked_confidentiel) { true }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(true) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the preivous avis is confidentiel' do
|
||||
let(:previous_avis_confidentiel) { true }
|
||||
|
||||
context 'when the user asked for a public avis' do
|
||||
let(:asked_confidentiel) { false }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(true) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with linked dossiers' do
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) }
|
||||
|
||||
context 'when the expert doesn’t share linked dossiers' do
|
||||
let(:invite_linked_dossiers) { false }
|
||||
|
||||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the expert also shares the linked dossiers' do
|
||||
context 'and the expert can access the linked dossiers' do
|
||||
let(:created_avis) { Avis.create(dossier: dossier, claimant: claimant, email: "toto3@gmail.com") }
|
||||
let(:linked_dossier) { Dossier.find_by(id: dossier.reload.champs.filter(&:dossier_link?).map(&:value).compact) }
|
||||
let(:linked_avis) { Avis.create(dossier: linked_dossier, claimant: claimant) }
|
||||
let(:invite_linked_dossiers) { true }
|
||||
|
||||
it 'sends one avis for the main dossier' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
|
||||
it 'sends another avis for the linked dossiers' do
|
||||
expect(Avis.count).to eq(old_avis_count + 2)
|
||||
expect(linked_avis.dossier).to eq(linked_dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'but the expert can’t access the linked dossier' do
|
||||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an expert signed in' do
|
||||
describe '#sign_up' do
|
||||
let(:invited_email) { 'invited@avis.com' }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:procedure) { dossier.procedure }
|
||||
let!(:avis) { create(:avis, experts_procedure: experts_procedure, claimant: claimant, dossier: dossier) }
|
||||
let(:invitations_email) { true }
|
||||
|
||||
context 'when the expert has already signed up and belongs to the invitation' do
|
||||
let!(:avis) { create(:avis, dossier: dossier, experts_procedure: experts_procedure, claimant: claimant) }
|
||||
|
||||
context 'when the expert is authenticated' do
|
||||
before do
|
||||
sign_in(expert.user)
|
||||
expert.user.update(last_sign_in_at: Time.zone.now)
|
||||
expert.user.reload
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: avis.expert.email }
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to expert_avis_url(avis.procedure, avis) }
|
||||
end
|
||||
|
||||
context 'when the expert is not authenticated' do
|
||||
before do
|
||||
sign_in(expert.user)
|
||||
expert.user.update(last_sign_in_at: Time.zone.now)
|
||||
expert.user.reload
|
||||
sign_out(expert.user)
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: avis.expert.email }
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to new_user_session_url }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the expert has already signed up / is authenticated and does not belong to the invitation' do
|
||||
let(:expert) { create(:expert) }
|
||||
let!(:avis) { create(:avis, email: invited_email, dossier: dossier, experts_procedure: experts_procedure) }
|
||||
|
||||
before do
|
||||
sign_in(expert.user)
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: avis.expert.email }
|
||||
end
|
||||
|
||||
# redirected to dossier but then the instructeur gonna be banished !
|
||||
it { is_expected.to redirect_to expert_avis_url(avis.procedure, avis) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,318 +3,28 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
render_views
|
||||
|
||||
let(:now) { Time.zone.parse('01/02/2345') }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [claimant]) }
|
||||
let(:another_procedure) { create(:procedure, :published, instructeurs: [claimant]) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||
let!(:avis_without_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur) }
|
||||
let!(:avis_with_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur, answer: 'yop') }
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure) }
|
||||
let!(:avis_without_answer) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure) }
|
||||
|
||||
before { sign_in(instructeur.user) }
|
||||
|
||||
describe '#index' do
|
||||
before { get :index }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis_by_procedure).flatten).to include(procedure) }
|
||||
it { expect(assigns(:avis_by_procedure).flatten).not_to include(another_procedure) }
|
||||
end
|
||||
|
||||
describe '#procedure' do
|
||||
before { get :procedure, params: { procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis_a_donner)).to match([avis_without_answer]) }
|
||||
it { expect(assigns(:avis_donnes)).to match([avis_with_answer]) }
|
||||
it { expect(assigns(:statut)).to eq('a-donner') }
|
||||
|
||||
context 'with a statut equal to donnes' do
|
||||
before { get :procedure, params: { statut: 'donnes', procedure_id: procedure.id } }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('donnes') }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
subject { get :show, params: { id: avis_with_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
context 'with a valid avis' do
|
||||
before { subject }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_with_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
context 'with a revoked avis' do
|
||||
it "refuse l'accès au dossier" do
|
||||
avis_with_answer.update!(revoked_at: Time.zone.now)
|
||||
subject
|
||||
expect(flash.alert).to eq("Vous n'avez plus accès à ce dossier.")
|
||||
expect(response).to redirect_to(root_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#instruction' do
|
||||
before { get :instruction, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
describe '#messagerie' do
|
||||
before { get :messagerie, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to have_http_status(:success) }
|
||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
describe '#bilans_bdf' do
|
||||
before { get :bilans_bdf, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||
|
||||
it { expect(response).to redirect_to(instructeur_avis_path(avis_without_answer)) }
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
context 'without attachment' do
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
patch :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer' } }
|
||||
avis_without_answer.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
it 'should be ok' do
|
||||
expect(response).to redirect_to(instruction_instructeur_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(avis_without_answer.answer).to eq('answer')
|
||||
expect(avis_without_answer.piece_justificative_file).to_not be_attached
|
||||
expect(dossier.reload.last_avis_updated_at).to eq(now)
|
||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with attachment' do
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
|
||||
before do
|
||||
post :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer', piece_justificative_file: file } }
|
||||
avis_without_answer.reload
|
||||
end
|
||||
|
||||
it 'should be ok' do
|
||||
expect(response).to redirect_to(instruction_instructeur_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(avis_without_answer.answer).to eq('answer')
|
||||
expect(avis_without_answer.piece_justificative_file).to be_attached
|
||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_commentaire' do
|
||||
let(:file) { nil }
|
||||
let(:scan_result) { true }
|
||||
let(:now) { Time.zone.parse("14/07/1789") }
|
||||
|
||||
subject { post :create_commentaire, params: { id: avis_without_answer.id, procedure_id: procedure.id, commentaire: { body: 'commentaire body', piece_jointe: file } } }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
it do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to(messagerie_instructeur_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(dossier.commentaires.map(&:body)).to match(['commentaire body'])
|
||||
expect(dossier.reload.last_commentaire_updated_at).to eq(now)
|
||||
end
|
||||
|
||||
context "with a file" do
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
|
||||
it do
|
||||
subject
|
||||
expect(Commentaire.last.piece_jointe.filename).to eq("piece_justificative_0.pdf")
|
||||
end
|
||||
|
||||
it { expect { subject }.to change(Commentaire, :count).by(1) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#expert_cannot_invite_another_expert' do
|
||||
let!(:previous_avis) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur, confidentiel: previous_avis_confidentiel) }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:intro) { 'introduction' }
|
||||
let(:emails) { ["toto@totomail.com"] }
|
||||
let(:invite_linked_dossiers) { nil }
|
||||
|
||||
before do
|
||||
Flipper.enable_actor(:expert_not_allowed_to_invite, procedure)
|
||||
post :create_avis, params: { id: previous_avis.id, procedure_id: procedure.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers, introduction_file: @introduction_file } }
|
||||
end
|
||||
|
||||
context 'when the expert cannot invite another expert' do
|
||||
let(:asked_confidentiel) { false }
|
||||
it { expect(flash.alert).to eq("Cette démarche ne vous permet pas de demander un avis externe") }
|
||||
it { expect(response).to redirect_to(instruction_instructeur_avis_path(procedure, previous_avis)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_avis' do
|
||||
let!(:previous_avis) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur, confidentiel: previous_avis_confidentiel) }
|
||||
let(:emails) { ['a@b.com'] }
|
||||
let(:intro) { 'introduction' }
|
||||
let(:created_avis) { Avis.last }
|
||||
let!(:old_avis_count) { Avis.count }
|
||||
let(:invite_linked_dossiers) { nil }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
@introduction_file = fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf')
|
||||
post :create_avis, params: { id: previous_avis.id, procedure_id: procedure.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers, introduction_file: @introduction_file } }
|
||||
created_avis.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
context 'when an invalid email' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:emails) { ["toto.fr"] }
|
||||
|
||||
it { expect(response).to render_template :instruction }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(Avis.last).to eq(previous_avis) }
|
||||
it { expect(dossier.last_avis_updated_at).to eq(nil) }
|
||||
end
|
||||
|
||||
context 'ask review with attachment' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:emails) { ["toto@totomail.com"] }
|
||||
|
||||
it { expect(created_avis.introduction_file).to be_attached }
|
||||
it { expect(created_avis.introduction_file.filename).to eq("piece_justificative_0.pdf") }
|
||||
it { expect(created_avis.dossier.reload.last_avis_updated_at).to eq(now) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à toto@totomail.com") }
|
||||
end
|
||||
|
||||
context 'with multiple emails' do
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:emails) { ["toto.fr,titi@titimail.com"] }
|
||||
|
||||
it { expect(response).to render_template :instruction }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à titi@titimail.com") }
|
||||
it { expect(Avis.count).to eq(old_avis_count + 1) }
|
||||
it { expect(created_avis.email).to eq("titi@titimail.com") }
|
||||
end
|
||||
|
||||
context 'when the previous avis is public' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
|
||||
context 'when the user asked for a public avis' do
|
||||
let(:asked_confidentiel) { false }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(false) }
|
||||
it { expect(created_avis.email).to eq(emails.last) }
|
||||
it { expect(created_avis.introduction).to eq(intro) }
|
||||
it { expect(created_avis.dossier).to eq(previous_avis.dossier) }
|
||||
it { expect(created_avis.claimant).to eq(instructeur) }
|
||||
it { expect(response).to redirect_to(instruction_instructeur_avis_path(previous_avis.procedure, previous_avis)) }
|
||||
end
|
||||
|
||||
context 'when the user asked for a confidentiel avis' do
|
||||
let(:asked_confidentiel) { true }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(true) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the preivous avis is confidentiel' do
|
||||
let(:previous_avis_confidentiel) { true }
|
||||
|
||||
context 'when the user asked for a public avis' do
|
||||
let(:asked_confidentiel) { false }
|
||||
|
||||
it { expect(created_avis.confidentiel).to be(true) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with linked dossiers' do
|
||||
let(:asked_confidentiel) { false }
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) }
|
||||
|
||||
context 'when the expert doesn’t share linked dossiers' do
|
||||
let(:invite_linked_dossiers) { false }
|
||||
|
||||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(created_avis.email).to eq("a@b.com")
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the expert also shares the linked dossiers' do
|
||||
let(:invite_linked_dossiers) { true }
|
||||
|
||||
context 'and the expert can access the linked dossiers' do
|
||||
let(:created_avis) { Avis.last(2).first }
|
||||
let(:linked_avis) { Avis.last }
|
||||
let(:linked_dossier) { Dossier.find_by(id: dossier.reload.champs.filter(&:dossier_link?).map(&:value).compact) }
|
||||
let(:invite_linked_dossiers) do
|
||||
instructeur.assign_to_procedure(linked_dossier.procedure)
|
||||
true
|
||||
end
|
||||
|
||||
it 'sends one avis for the main dossier' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(created_avis.email).to eq("a@b.com")
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
|
||||
it 'sends another avis for the linked dossiers' do
|
||||
expect(Avis.count).to eq(old_avis_count + 2)
|
||||
expect(linked_avis.dossier).to eq(linked_dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'but the expert can’t access the linked dossier' do
|
||||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(created_avis.email).to eq("a@b.com")
|
||||
expect(created_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#revoker" do
|
||||
let(:avis) { create(:avis, claimant: instructeur) }
|
||||
let(:procedure) { avis.procedure }
|
||||
before do
|
||||
patch :revoquer, params: { procedure_id: procedure.id, id: avis.id }
|
||||
end
|
||||
|
||||
it "revoke the dossier" do
|
||||
patch :revoquer, params: { procedure_id: procedure.id, id: avis.id }
|
||||
|
||||
expect(flash.notice).to eq("#{avis.email} ne peut plus donner son avis sur ce dossier.")
|
||||
expect(flash.notice).to eq("#{avis.expert.email} ne peut plus donner son avis sur ce dossier.")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'revive' do
|
||||
let(:avis) { create(:avis, claimant: instructeur, email: 'expert@gouv.fr') }
|
||||
let(:procedure) { avis.procedure }
|
||||
|
||||
before do
|
||||
allow(AvisMailer).to receive(:avis_invitation).and_return(double(deliver_later: nil))
|
||||
end
|
||||
|
@ -322,141 +32,7 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
it 'sends a reminder to the expert' do
|
||||
get :revive, params: { procedure_id: procedure.id, id: avis.id }
|
||||
expect(AvisMailer).to have_received(:avis_invitation).once.with(avis)
|
||||
expect(flash.notice).to eq("Un mail de relance a été envoyé à #{avis.email}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a instructeur signed in' do
|
||||
describe '#sign_up' do
|
||||
let(:invited_email) { 'invited@avis.com' }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:procedure) { dossier.procedure }
|
||||
let!(:avis) { create(:avis, email: invited_email, dossier: dossier) }
|
||||
let(:invitations_email) { true }
|
||||
|
||||
context 'when the new instructeur has never signed up' do
|
||||
before do
|
||||
expect(Avis).to receive(:avis_exists_and_email_belongs_to_avis?)
|
||||
.with(avis.id.to_s, invited_email)
|
||||
.and_return(invitations_email)
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: invited_email }
|
||||
end
|
||||
|
||||
context 'when the email belongs to the invitation' do
|
||||
it { expect(subject.status).to eq(200) }
|
||||
it { expect(assigns(:email)).to eq(invited_email) }
|
||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||
end
|
||||
|
||||
context 'when the email does not belong to the invitation' do
|
||||
let(:invitations_email) { false }
|
||||
|
||||
it { is_expected.to redirect_to root_path }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instructeur has already signed up and belongs to the invitation' do
|
||||
let(:instructeur) { create(:instructeur, email: invited_email) }
|
||||
let!(:avis) { create(:avis, dossier: dossier, instructeur: instructeur) }
|
||||
|
||||
context 'when the instructeur is authenticated' do
|
||||
before do
|
||||
sign_in(instructeur.user)
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: invited_email }
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to instructeur_avis_url(avis.procedure, avis) }
|
||||
end
|
||||
|
||||
context 'when the instructeur is not authenticated' do
|
||||
before do
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: invited_email }
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to new_user_session_url }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instructeur has already signed up / is authenticated and does not belong to the invitation' do
|
||||
let(:instructeur) { create(:instructeur, email: 'other@gmail.com') }
|
||||
let!(:avis) { create(:avis, email: invited_email, dossier: dossier) }
|
||||
|
||||
before do
|
||||
sign_in(instructeur.user)
|
||||
get :sign_up, params: { id: avis.id, procedure_id: procedure.id, email: invited_email }
|
||||
end
|
||||
|
||||
# redirected to dossier but then the instructeur gonna be banished !
|
||||
it { is_expected.to redirect_to instructeur_avis_url(avis.procedure, avis) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_instructeur' do
|
||||
let(:existing_user_mail) { 'dummy@example.org' }
|
||||
let!(:existing_user) { create(:user, email: existing_user_mail) }
|
||||
let(:invited_email) { 'invited@avis.com' }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:procedure) { dossier.procedure }
|
||||
let!(:avis) { create(:avis, email: invited_email, dossier: dossier) }
|
||||
let(:avis_id) { avis.id }
|
||||
let(:password) { 'my-s3cure-p4ssword' }
|
||||
let(:created_instructeur) { Instructeur.by_email(invited_email) }
|
||||
let(:invitations_email) { true }
|
||||
|
||||
before do
|
||||
allow(Avis).to receive(:link_avis_to_instructeur)
|
||||
expect(Avis).to receive(:avis_exists_and_email_belongs_to_avis?)
|
||||
.with(avis_id.to_s, invited_email)
|
||||
.and_return(invitations_email)
|
||||
|
||||
post :create_instructeur, params: {
|
||||
id: avis_id,
|
||||
procedure_id: procedure.id,
|
||||
email: invited_email,
|
||||
user: {
|
||||
password: password
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when the email does not belong to the invitation' do
|
||||
let(:invitations_email) { false }
|
||||
|
||||
it { is_expected.to redirect_to root_path }
|
||||
end
|
||||
|
||||
context 'when the email belongs to the invitation' do
|
||||
context 'when the instructeur creation succeeds' do
|
||||
it { expect(created_instructeur).to be_present }
|
||||
it { expect(created_instructeur.user.valid_password?(password)).to be true }
|
||||
|
||||
it { expect(Avis).to have_received(:link_avis_to_instructeur) }
|
||||
|
||||
it { expect(subject.current_instructeur).to eq(created_instructeur) }
|
||||
it { is_expected.to redirect_to instructeur_all_avis_path }
|
||||
|
||||
it 'creates a corresponding user account for the email' do
|
||||
user = User.find_by(email: invited_email)
|
||||
expect(user).to be_present
|
||||
end
|
||||
|
||||
context 'when there already is a user account with the same email' do
|
||||
let(:existing_user_mail) { invited_email }
|
||||
|
||||
it 'still creates a instructeur account' do
|
||||
expect(created_instructeur).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instructeur creation fails' do
|
||||
let(:password) { '' }
|
||||
|
||||
it { expect(created_instructeur).to be_nil }
|
||||
it { is_expected.to redirect_to sign_up_instructeur_avis_path(procedure.id, avis_id, invited_email) }
|
||||
it { expect(flash.alert).to eq(['Le mot de passe doit être rempli']) }
|
||||
end
|
||||
expect(flash.notice).to eq("Un mail de relance a été envoyé à #{avis.expert.email}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -434,6 +434,8 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
end
|
||||
|
||||
describe "#create_avis" do
|
||||
let(:expert) { create(:expert) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: dossier.procedure) }
|
||||
let(:invite_linked_dossiers) { false }
|
||||
let(:saved_avis) { dossier.avis.first }
|
||||
let!(:old_avis_count) { Avis.count }
|
||||
|
@ -442,7 +444,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
post :create_avis, params: {
|
||||
procedure_id: procedure.id,
|
||||
dossier_id: dossier.id,
|
||||
avis: { emails: emails, introduction: 'intro', confidentiel: true, invite_linked_dossiers: invite_linked_dossiers }
|
||||
avis: { emails: emails, introduction: 'intro', confidentiel: true, invite_linked_dossiers: invite_linked_dossiers, claimant: instructeur, experts_procedure: experts_procedure }
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -466,7 +468,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
subject
|
||||
end
|
||||
|
||||
it { expect(saved_avis.email).to eq('email@a.com') }
|
||||
it { expect(saved_avis.expert.email).to eq('email@a.com') }
|
||||
it { expect(saved_avis.introduction).to eq('intro') }
|
||||
it { expect(saved_avis.confidentiel).to eq(true) }
|
||||
it { expect(saved_avis.dossier).to eq(dossier) }
|
||||
|
@ -493,7 +495,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à titi@titimail.com") }
|
||||
it { expect(Avis.count).to eq(old_avis_count + 1) }
|
||||
it { expect(saved_avis.email).to eq("titi@titimail.com") }
|
||||
it { expect(saved_avis.expert.email).to eq("titi@titimail.com") }
|
||||
end
|
||||
|
||||
context 'with linked dossiers' do
|
||||
|
@ -507,7 +509,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à email@a.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(saved_avis.email).to eq("email@a.com")
|
||||
expect(saved_avis.expert.email).to eq("email@a.com")
|
||||
expect(saved_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
|
@ -526,7 +528,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
|
||||
it 'sends one avis for the main dossier' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à email@a.com")
|
||||
expect(saved_avis.email).to eq("email@a.com")
|
||||
expect(saved_avis.expert.email).to eq("email@a.com")
|
||||
expect(saved_avis.dossier).to eq(dossier)
|
||||
end
|
||||
|
||||
|
@ -540,7 +542,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
it 'sends a single avis for the main dossier, but doesn’t give access to the linked dossiers' do
|
||||
expect(flash.notice).to eq("Une demande d'avis a été envoyée à email@a.com")
|
||||
expect(Avis.count).to eq(old_avis_count + 1)
|
||||
expect(saved_avis.email).to eq("email@a.com")
|
||||
expect(saved_avis.expert.email).to eq("email@a.com")
|
||||
expect(saved_avis.dossier).to eq(dossier)
|
||||
end
|
||||
end
|
||||
|
@ -552,7 +554,9 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
describe "#show" do
|
||||
context "when the dossier is exported as PDF" do
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: instructeurs) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:dossier) do
|
||||
create(:dossier,
|
||||
:accepte,
|
||||
|
@ -562,7 +566,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
:with_entreprise,
|
||||
:with_commentaires, procedure: procedure)
|
||||
end
|
||||
let(:avis) { create(:avis, dossier: dossier, instructeur: instructeur) }
|
||||
let!(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure) }
|
||||
|
||||
subject do
|
||||
avis
|
||||
|
|
|
@ -40,47 +40,6 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe "before_action: redirect_to_avis_if_needed" do
|
||||
it "is present" do
|
||||
before_actions = Instructeurs::ProceduresController
|
||||
._process_action_callbacks
|
||||
.filter { |process_action_callbacks| process_action_callbacks.kind == :before }
|
||||
.map(&:filter)
|
||||
|
||||
expect(before_actions).to include(:redirect_to_avis_if_needed)
|
||||
end
|
||||
end
|
||||
|
||||
describe "redirect_to_avis_if_needed" do
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
|
||||
before do
|
||||
expect(@controller).to receive(:current_instructeur).at_least(:once).and_return(instructeur)
|
||||
allow(@controller).to receive(:redirect_to)
|
||||
end
|
||||
|
||||
context "when a instructeur has some procedures" do
|
||||
let!(:some_procedure) { create(:procedure, instructeurs: [instructeur]) }
|
||||
|
||||
before { @controller.send(:redirect_to_avis_if_needed) }
|
||||
|
||||
it "does not redirects nor flash" do
|
||||
expect(@controller).not_to have_received(:redirect_to)
|
||||
end
|
||||
end
|
||||
|
||||
context "when a instructeur has no procedure and some avis" do
|
||||
before do
|
||||
Avis.create!(dossier: create(:dossier), claimant: create(:instructeur), instructeur: instructeur)
|
||||
@controller.send(:redirect_to_avis_if_needed)
|
||||
end
|
||||
|
||||
it "redirects avis" do
|
||||
expect(@controller).to have_received(:redirect_to).with(instructeur_all_avis_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#index" do
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
subject { get :index }
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
describe InvitesController, type: :controller do
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
let(:email) { 'plop@octo.com' }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
|
||||
describe '#POST create' do
|
||||
let(:invite) { Invite.last }
|
||||
|
@ -23,7 +26,7 @@ describe InvitesController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when instructeur is invited for avis on dossier' do
|
||||
before { Avis.create(instructeur: signed_in_profile.instructeur, claimant: create(:instructeur), dossier: dossier) }
|
||||
before { Avis.create(experts_procedure: experts_procedure, claimant: create(:instructeur), dossier: dossier) }
|
||||
|
||||
it_behaves_like "he can not create invitation"
|
||||
end
|
||||
|
|
77
spec/features/experts/expert_spec.rb
Normal file
77
spec/features/experts/expert_spec.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
feature 'Inviting an expert:' do
|
||||
include ActiveJob::TestHelper
|
||||
include ActionView::Helpers
|
||||
|
||||
context 'as an invited Expert' do
|
||||
let(:expert) { create(:expert) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) }
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) }
|
||||
|
||||
context 'when I don’t already have an account' do
|
||||
scenario 'I can sign up' do
|
||||
visit sign_up_expert_avis_path(avis.dossier.procedure, avis, avis.expert.email)
|
||||
|
||||
expect(page).to have_field('Email', with: avis.expert.email, disabled: true)
|
||||
fill_in 'Mot de passe', with: 'This is a very complicated password !'
|
||||
click_on 'Créer un compte'
|
||||
|
||||
expect(page).to have_current_path(expert_all_avis_path)
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when I already have an existing account' do
|
||||
before do
|
||||
avis.expert.user.update!(last_sign_in_at: Time.zone.now)
|
||||
avis.expert.user.reload
|
||||
end
|
||||
scenario 'I can sign in' do
|
||||
visit sign_up_expert_avis_path(avis.dossier.procedure, avis, avis.expert.email)
|
||||
|
||||
expect(page).to have_current_path(new_user_session_path)
|
||||
login_as avis.expert.user, scope: :user
|
||||
sign_in_with(avis.expert.email, 'This is a very complicated password !')
|
||||
click_on 'Passer en expert'
|
||||
expect(page).to have_current_path(expert_all_avis_path)
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'I can give an answer' do
|
||||
avis # create avis
|
||||
login_as expert.user, scope: :user
|
||||
|
||||
visit expert_all_avis_path
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
expect(page).to have_text('0 avis donnés')
|
||||
|
||||
click_on '1 avis à donner'
|
||||
click_on avis.dossier.user.email
|
||||
within('.tabs') { click_on 'Avis' }
|
||||
expect(page).to have_text("Demandeur : #{avis.claimant.email}")
|
||||
expect(page).to have_text('Cet avis est confidentiel')
|
||||
|
||||
fill_in 'avis_answer', with: 'Ma réponse d’expert : c’est un oui.'
|
||||
find('.attachment input[name="avis[piece_justificative_file]"]').attach_file(Rails.root + 'spec/fixtures/files/RIB.pdf')
|
||||
click_on 'Envoyer votre avis'
|
||||
|
||||
expect(page).to have_content('Votre réponse est enregistrée')
|
||||
expect(page).to have_content('Ma réponse d’expert : c’est un oui.')
|
||||
expect(page).to have_content('RIB.pdf')
|
||||
|
||||
within('.breadcrumbs') { click_on 'Avis' }
|
||||
expect(page).to have_text('0 avis à donner')
|
||||
expect(page).to have_text('1 avis donné')
|
||||
end
|
||||
|
||||
# TODO
|
||||
# scenario 'I can read other experts advices' do
|
||||
# end
|
||||
|
||||
# scenario 'I can invite other experts' do
|
||||
# end
|
||||
end
|
||||
end
|
|
@ -3,7 +3,8 @@ feature 'Inviting an expert:' do
|
|||
include ActionView::Helpers
|
||||
|
||||
let(:instructeur) { create(:instructeur, password: 'my-s3cure-p4ssword') }
|
||||
let(:expert) { create(:instructeur, password: expert_password) }
|
||||
let(:expert) { create(:expert, password: expert_password) }
|
||||
let(:expert2) { create(:expert, password: expert_password) }
|
||||
let(:expert_password) { 'mot de passe d’expert' }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) }
|
||||
|
@ -20,7 +21,7 @@ feature 'Inviting an expert:' do
|
|||
click_on 'Avis externes'
|
||||
expect(page).to have_current_path(avis_instructeur_dossier_path(procedure, dossier))
|
||||
|
||||
fill_in 'avis_emails', with: 'expert1@exemple.fr, expert2@exemple.fr'
|
||||
fill_in 'avis_emails', with: "#{expert.email}, #{expert2.email}"
|
||||
fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.'
|
||||
check 'avis_invite_linked_dossiers'
|
||||
page.select 'confidentiel', from: 'avis_confidentiel'
|
||||
|
@ -31,23 +32,24 @@ feature 'Inviting an expert:' do
|
|||
expect(page).to have_content('Une demande d\'avis a été envoyée')
|
||||
expect(page).to have_content('Avis des invités')
|
||||
within('.list-avis') do
|
||||
expect(page).to have_content('expert1@exemple.fr')
|
||||
expect(page).to have_content('expert2@exemple.fr')
|
||||
expect(page).to have_content(expert.email.to_s)
|
||||
expect(page).to have_content(expert2.email.to_s)
|
||||
expect(page).to have_content('Bonjour, merci de me donner votre avis sur ce dossier.')
|
||||
end
|
||||
|
||||
expect(Avis.count).to eq(4)
|
||||
expect(emails_sent_to('expert1@exemple.fr').size).to eq(1)
|
||||
expect(emails_sent_to('expert2@exemple.fr').size).to eq(1)
|
||||
expect(emails_sent_to(expert.email.to_s).size).to eq(1)
|
||||
expect(emails_sent_to(expert2.email.to_s).size).to eq(1)
|
||||
|
||||
invitation_email = open_email('expert2@exemple.fr')
|
||||
avis = Avis.find_by(email: 'expert2@exemple.fr', dossier: dossier)
|
||||
sign_up_link = sign_up_instructeur_avis_path(avis.dossier.procedure, avis, avis.email)
|
||||
invitation_email = open_email(expert.email.to_s)
|
||||
avis = Avis.find_by(expert: expert.id)
|
||||
sign_up_link = sign_up_expert_avis_path(avis.dossier.procedure, avis, avis.expert.email)
|
||||
expect(invitation_email.body).to include(sign_up_link)
|
||||
end
|
||||
|
||||
context 'when experts submitted their answer' do
|
||||
let!(:answered_avis) { create(:avis, :with_answer, dossier: dossier, claimant: instructeur, email: expert.email) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let!(:answered_avis) { create(:avis, :with_answer, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure) }
|
||||
|
||||
scenario 'I can read the expert answer' do
|
||||
login_as instructeur.user, scope: :user
|
||||
|
@ -55,80 +57,11 @@ feature 'Inviting an expert:' do
|
|||
|
||||
click_on 'Avis externes'
|
||||
|
||||
expect(page).to have_content(expert.email)
|
||||
expect(page).to have_content(answered_avis.expert.email)
|
||||
answered_avis.answer.split("\n").each do |answer_line|
|
||||
expect(page).to have_content(answer_line)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'as an invited Expert' do
|
||||
let(:avis_email) { expert.email }
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, email: avis_email, confidentiel: true) }
|
||||
|
||||
context 'when I don’t already have an account' do
|
||||
let(:avis_email) { 'not-signed-up-expert@exemple.fr' }
|
||||
|
||||
scenario 'I can sign up' do
|
||||
visit sign_up_instructeur_avis_path(avis.dossier.procedure, avis, avis_email)
|
||||
|
||||
expect(page).to have_field('Email', with: avis_email, disabled: true)
|
||||
fill_in 'Mot de passe', with: 'This is a very complicated password !'
|
||||
click_on 'Créer un compte'
|
||||
|
||||
expect(page).to have_current_path(instructeur_all_avis_path)
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when I already have an existing account' do
|
||||
let(:avis_email) { expert.email }
|
||||
|
||||
scenario 'I can sign in' do
|
||||
visit sign_up_instructeur_avis_path(avis.dossier.procedure, avis, avis_email)
|
||||
|
||||
expect(page).to have_current_path(new_user_session_path)
|
||||
sign_in_with(expert.email, expert_password)
|
||||
|
||||
expect(page).to have_current_path(instructeur_all_avis_path)
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'I can give an answer' do
|
||||
avis # create avis
|
||||
login_as expert.user, scope: :user
|
||||
|
||||
visit instructeur_all_avis_path
|
||||
expect(page).to have_text('1 avis à donner')
|
||||
expect(page).to have_text('0 avis donnés')
|
||||
|
||||
click_on '1 avis à donner'
|
||||
click_on avis.dossier.user.email
|
||||
|
||||
within('.tabs') { click_on 'Avis' }
|
||||
expect(page).to have_text("Demandeur : #{instructeur.email}")
|
||||
expect(page).to have_text('Cet avis est confidentiel')
|
||||
|
||||
fill_in 'avis_answer', with: 'Ma réponse d’expert : c’est un oui.'
|
||||
find('.attachment input[name="avis[piece_justificative_file]"]').attach_file(Rails.root + 'spec/fixtures/files/RIB.pdf')
|
||||
click_on 'Envoyer votre avis'
|
||||
|
||||
expect(page).to have_content('Votre réponse est enregistrée')
|
||||
expect(page).to have_content('Ma réponse d’expert : c’est un oui.')
|
||||
expect(page).to have_content('RIB.pdf')
|
||||
|
||||
within('.new-header') { click_on 'Avis' }
|
||||
expect(page).to have_text('0 avis à donner')
|
||||
expect(page).to have_text('1 avis donné')
|
||||
end
|
||||
|
||||
# TODO
|
||||
# scenario 'I can read other experts advices' do
|
||||
# end
|
||||
|
||||
# scenario 'I can invite other experts' do
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,14 +24,6 @@ describe DossierLinkHelper do
|
|||
it { expect(helper.dossier_linked_path(instructeur, dossier)).to eq(instructeur_dossier_path(dossier.procedure, dossier)) }
|
||||
end
|
||||
|
||||
context "when access as expert" do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let!(:avis) { create(:avis, dossier: dossier, instructeur: instructeur) }
|
||||
|
||||
it { expect(helper.dossier_linked_path(instructeur, dossier)).to eq(instructeur_avis_path(avis.dossier.procedure, avis)) }
|
||||
end
|
||||
|
||||
context "when access as user" do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
RSpec.describe AvisMailer, type: :mailer do
|
||||
describe '.avis_invitation' do
|
||||
let(:avis) { create(:avis) }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: dossier.procedure) }
|
||||
let(:avis) { Avis.create(dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, introduction: 'intro') }
|
||||
|
||||
subject { described_class.avis_invitation(avis) }
|
||||
|
||||
|
@ -10,12 +14,7 @@ RSpec.describe AvisMailer, type: :mailer do
|
|||
it { expect(subject.body).to include(instructeur_avis_url(avis.dossier.procedure.id, avis)) }
|
||||
|
||||
context 'when the recipient is not already registered' do
|
||||
before do
|
||||
avis.email = 'instructeur@email.com'
|
||||
avis.instructeur = nil
|
||||
end
|
||||
|
||||
it { expect(subject.body).to include(sign_up_instructeur_avis_url(avis.dossier.procedure.id, avis.id, avis.email)) }
|
||||
it { expect(subject.body).to include(sign_up_expert_avis_url(avis.dossier.procedure.id, avis.id, avis.expert.email)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,22 +3,16 @@ RSpec.describe Avis, type: :model do
|
|||
|
||||
describe '#email_to_display' do
|
||||
let(:invited_email) { 'invited@avis.com' }
|
||||
let!(:avis) do
|
||||
avis = create(:avis, email: invited_email, dossier: create(:dossier))
|
||||
avis.instructeur = nil
|
||||
avis
|
||||
end
|
||||
let(:expert) { create(:expert) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
|
||||
subject { avis.email_to_display }
|
||||
|
||||
context 'when instructeur is not known' do
|
||||
it { is_expected.to eq(invited_email) }
|
||||
end
|
||||
context 'when expert is known' do
|
||||
let!(:avis) { create(:avis, claimant: claimant, dossier: create(:dossier), experts_procedure: experts_procedure) }
|
||||
|
||||
context 'when instructeur is known' do
|
||||
let!(:avis) { create(:avis, email: nil, instructeur: create(:instructeur), dossier: create(:dossier)) }
|
||||
|
||||
it { is_expected.to eq(avis.instructeur.email) }
|
||||
it { is_expected.to eq(avis.expert.email) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -34,28 +28,6 @@ RSpec.describe Avis, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe ".link_avis_to_instructeur" do
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
|
||||
subject { Avis.link_avis_to_instructeur(instructeur) }
|
||||
|
||||
context 'when there are 2 avis linked by email to a instructeur' do
|
||||
let!(:avis) { create(:avis, email: instructeur.email, instructeur: nil) }
|
||||
let!(:avis2) { create(:avis, email: instructeur.email, instructeur: nil) }
|
||||
|
||||
before do
|
||||
subject
|
||||
avis.reload
|
||||
avis2.reload
|
||||
end
|
||||
|
||||
it { expect(avis.email).to be_nil }
|
||||
it { expect(avis.instructeur).to eq(instructeur) }
|
||||
it { expect(avis2.email).to be_nil }
|
||||
it { expect(avis2.instructeur).to eq(instructeur) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "an avis is linked to an expert_procedure" do
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:expert) { create(:expert) }
|
||||
|
@ -102,31 +74,14 @@ RSpec.describe Avis, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#try_to_assign_instructeur' do
|
||||
let!(:instructeur) { create(:instructeur) }
|
||||
let(:avis) { create(:avis, claimant: claimant, email: email, dossier: create(:dossier)) }
|
||||
|
||||
context 'when the email belongs to a instructeur' do
|
||||
let(:email) { instructeur.email }
|
||||
|
||||
it { expect(avis.instructeur).to eq(instructeur) }
|
||||
it { expect(avis.email).to be_nil }
|
||||
end
|
||||
|
||||
context 'when the email does not belongs to a instructeur' do
|
||||
let(:email) { 'unknown@email' }
|
||||
|
||||
it { expect(avis.instructeur).to be_nil }
|
||||
it { expect(avis.email).to eq(email) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "email sanitization" do
|
||||
subject { Avis.create(claimant: claimant, email: email, dossier: create(:dossier), instructeur: create(:instructeur)) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let!(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
subject { Avis.create(claimant: claimant, email: email, experts_procedure: experts_procedure, dossier: create(:dossier)) }
|
||||
|
||||
context "when there is no email" do
|
||||
let(:email) { nil }
|
||||
|
||||
it { expect(subject.email).to be_nil }
|
||||
end
|
||||
|
||||
|
@ -191,12 +146,13 @@ RSpec.describe Avis, type: :model do
|
|||
let(:procedure) { create(:procedure, :published, instructeurs: instructeurs) }
|
||||
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||
let(:claimant_expert) { create(:instructeur) }
|
||||
let(:expert) { create(:instructeur) }
|
||||
let(:another_expert) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:another_expert) { create(:expert) }
|
||||
|
||||
context "when avis claimed by an expert" do
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: claimant_expert, instructeur: expert) }
|
||||
let(:another_avis) { create(:avis, dossier: dossier, claimant: instructeur, instructeur: another_expert) }
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: claimant_expert, experts_procedure: experts_procedure) }
|
||||
let(:another_avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure) }
|
||||
it "is revokable by this expert or any instructeurs of the dossier" do
|
||||
expect(avis.revokable_by?(claimant_expert)).to be_truthy
|
||||
expect(avis.revokable_by?(another_expert)).to be_falsy
|
||||
|
@ -205,8 +161,13 @@ RSpec.describe Avis, type: :model do
|
|||
end
|
||||
|
||||
context "when avis claimed by an instructeur" do
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, instructeur: expert) }
|
||||
let(:another_avis) { create(:avis, dossier: dossier, claimant: expert, instructeur: another_expert) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:expert_2) { create(:expert) }
|
||||
let!(:procedure) { create(:procedure, :published, instructeurs: instructeurs) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
let(:experts_procedure_2) { ExpertsProcedure.create(expert: expert_2, procedure: procedure) }
|
||||
let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure) }
|
||||
let(:another_avis) { create(:avis, dossier: dossier, claimant: expert, experts_procedure: experts_procedure_2) }
|
||||
let(:another_instructeur) { create(:instructeur) }
|
||||
let(:instructeurs) { [instructeur, another_instructeur] }
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ shared_examples 'champ_spec' do
|
|||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||
end
|
||||
|
||||
context 'when multiple_drop_down_list mandatory and blank' do
|
||||
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) }
|
||||
let(:value) { '[]' }
|
||||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||
end
|
||||
|
||||
context 'when not blank' do
|
||||
let(:value) { 'yop' }
|
||||
it { expect(champ.mandatory_and_blank?).to be(false) }
|
||||
|
|
|
@ -307,49 +307,50 @@ describe Dossier do
|
|||
let!(:instructeur) { create(:instructeur) }
|
||||
let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||
let!(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)) }
|
||||
|
||||
let!(:expert_1) { create(:instructeur) }
|
||||
let!(:expert_2) { create(:instructeur) }
|
||||
let!(:experts_procedure) { ExpertsProcedure.create(expert: expert_1, procedure: procedure) }
|
||||
let!(:experts_procedure_2) { ExpertsProcedure.create(expert: expert_2, procedure: procedure) }
|
||||
let!(:expert_1) { create(:expert) }
|
||||
let!(:expert_2) { create(:expert) }
|
||||
|
||||
context 'when there is a public advice asked from the dossiers instructeur' do
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, instructeur: expert_1, confidentiel: false) }
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: false) }
|
||||
|
||||
it { expect(dossier.avis_for(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_instructeur(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_2)).to match([avis]) }
|
||||
end
|
||||
|
||||
context 'when there is a private advice asked from the dossiers instructeur' do
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, instructeur: expert_1, confidentiel: true) }
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) }
|
||||
|
||||
it { expect(dossier.avis_for(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_2)).to match([]) }
|
||||
it { expect(dossier.avis_for_instructeur(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_2)).not_to match([avis]) }
|
||||
end
|
||||
|
||||
context 'when there is a public advice asked from one expert to another' do
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: expert_1, instructeur: expert_2, confidentiel: false) }
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure_2, confidentiel: false) }
|
||||
|
||||
it { expect(dossier.avis_for(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_instructeur(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_2)).to match([avis]) }
|
||||
end
|
||||
|
||||
context 'when there is a private advice asked from one expert to another' do
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: expert_1, instructeur: expert_2, confidentiel: true) }
|
||||
let!(:avis) { Avis.create(dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure_2, confidentiel: true) }
|
||||
|
||||
it { expect(dossier.avis_for(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
|
||||
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_instructeur(instructeur)).to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_1)).not_to match([avis]) }
|
||||
it { expect(dossier.avis_for_expert(expert_2)).to match([avis]) }
|
||||
end
|
||||
|
||||
context 'when they are a lot of advice' do
|
||||
let!(:avis_1) { Avis.create(dossier: dossier, claimant: expert_1, instructeur: expert_2, confidentiel: false, created_at: Time.zone.parse('10/01/2010')) }
|
||||
let!(:avis_2) { Avis.create(dossier: dossier, claimant: expert_1, instructeur: expert_2, confidentiel: false, created_at: Time.zone.parse('9/01/2010')) }
|
||||
let!(:avis_3) { Avis.create(dossier: dossier, claimant: expert_1, instructeur: expert_2, confidentiel: false, created_at: Time.zone.parse('11/01/2010')) }
|
||||
let!(:avis_1) { Avis.create(dossier: dossier, claimant: expert_1, experts_procedure: experts_procedure_2, confidentiel: false, created_at: Time.zone.parse('10/01/2010'), tmp_expert_migrated: true) }
|
||||
let!(:avis_2) { Avis.create(dossier: dossier, claimant: expert_1, experts_procedure: experts_procedure_2, confidentiel: false, created_at: Time.zone.parse('9/01/2010'), tmp_expert_migrated: true) }
|
||||
let!(:avis_3) { Avis.create(dossier: dossier, claimant: expert_1, experts_procedure: experts_procedure_2, confidentiel: false, created_at: Time.zone.parse('11/01/2010'), tmp_expert_migrated: true) }
|
||||
|
||||
it { expect(dossier.avis_for(instructeur)).to match([avis_2, avis_1, avis_3]) }
|
||||
it { expect(dossier.avis_for(expert_1)).to match([avis_2, avis_1, avis_3]) }
|
||||
it { expect(dossier.avis_for_instructeur(instructeur)).to match([avis_2, avis_1, avis_3]) }
|
||||
it { expect(dossier.avis_for_expert(expert_1)).to match([avis_2, avis_1, avis_3]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
RSpec.describe ExpertsProcedure, type: :model do
|
||||
describe '#invited_expert_emails' do
|
||||
let!(:procedure) { create(:procedure, :published) }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:expert2) { create(:expert) }
|
||||
let(:expert3) { create(:expert) }
|
||||
|
@ -13,7 +14,7 @@ RSpec.describe ExpertsProcedure, type: :model do
|
|||
let!(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
context 'when a procedure has one avis and known instructeur' do
|
||||
let!(:avis) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: expert.email), experts_procedure: experts_procedure) }
|
||||
let!(:avis) { create(:avis, dossier: dossier, claimant: claimant, experts_procedure: experts_procedure) }
|
||||
|
||||
it { is_expected.to eq([experts_procedure]) }
|
||||
it { expect(procedure.experts.count).to eq(1) }
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
describe 'instructeurs/avis/instruction.html.haml', type: :view do
|
||||
let(:expert) { create(:instructeur) }
|
||||
let(:avis) { create(:avis, confidentiel: confidentiel, email: expert.email) }
|
||||
describe 'experts/avis/instruction.html.haml', type: :view do
|
||||
let(:expert) { create(:expert) }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let!(:avis) { create(:avis, confidentiel: confidentiel, claimant: claimant, experts_procedure: experts_procedure) }
|
||||
let!(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
|
||||
|
||||
before do
|
||||
assign(:avis, avis)
|
||||
assign(:new_avis, Avis.new)
|
||||
assign(:dossier, avis.dossier)
|
||||
allow(view).to receive(:current_instructeur).and_return(avis.instructeur)
|
||||
allow(view).to receive(:current_expert).and_return(avis.expert)
|
||||
end
|
||||
|
||||
subject { render }
|
|
@ -4,7 +4,10 @@ describe 'instructeurs/shared/avis/_list.html.haml', type: :view do
|
|||
subject { render 'instructeurs/shared/avis/list.html.haml', avis: avis, avis_seen_at: seen_at, current_instructeur: instructeur }
|
||||
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:avis) { [create(:avis, claimant: instructeur)] }
|
||||
let(:expert) { create(:expert) }
|
||||
let!(:dossier) { create(:dossier) }
|
||||
let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: dossier.procedure) }
|
||||
let(:avis) { [create(:avis, claimant: instructeur, experts_procedure: experts_procedure)] }
|
||||
let(:seen_at) { avis.first.created_at + 1.hour }
|
||||
|
||||
it { is_expected.to have_text(avis.first.introduction) }
|
||||
|
@ -17,7 +20,7 @@ describe 'instructeurs/shared/avis/_list.html.haml', type: :view do
|
|||
end
|
||||
|
||||
context 'with an answer' do
|
||||
let(:avis) { [create(:avis, :with_answer, claimant: instructeur)] }
|
||||
let(:avis) { [create(:avis, :with_answer, claimant: instructeur, experts_procedure: experts_procedure)] }
|
||||
|
||||
it 'renders the answer formatted with newlines' do
|
||||
expect(subject).to include(simple_format(avis.first.answer))
|
||||
|
|
|
@ -12,7 +12,6 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
|
||||
context "there are some champs" do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:avis) { create :avis, dossier: dossier, instructeur: instructeur }
|
||||
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: "on") }
|
||||
let(:champ2) { create(:champ_header_section, dossier: dossier, value: "Section") }
|
||||
let(:champ3) { create(:champ_explication, dossier: dossier, value: "mazette") }
|
||||
|
@ -20,8 +19,6 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
let(:champ5) { create(:champ_textarea, dossier: dossier, value: "Some long text in a textarea.") }
|
||||
let(:champs) { [champ1, champ2, champ3, champ4, champ5] }
|
||||
|
||||
before { dossier.avis << avis }
|
||||
|
||||
it "renders titles and values of champs" do
|
||||
expect(subject).to include(champ1.libelle)
|
||||
expect(subject).to include(champ1.value)
|
||||
|
@ -29,7 +26,6 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
expect(subject).to have_css(".header-section")
|
||||
expect(subject).to include(champ2.libelle)
|
||||
|
||||
expect(subject).to have_link("Dossier nº #{dossier.id}")
|
||||
expect(subject).to include(dossier.text_summary)
|
||||
|
||||
expect(subject).to include(champ5.libelle)
|
||||
|
|
Loading…
Reference in a new issue