commit
9488112005
27 changed files with 156 additions and 282 deletions
|
@ -1,16 +0,0 @@
|
||||||
@import "colors";
|
|
||||||
@import "constants";
|
|
||||||
|
|
||||||
#user-satisfaction {
|
|
||||||
text-align: center;
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
padding: 10px 5px;
|
|
||||||
margin: 10px 10px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -233,7 +233,10 @@ module Instructeurs
|
||||||
private
|
private
|
||||||
|
|
||||||
def dossier
|
def dossier
|
||||||
@dossier ||= current_instructeur.dossiers.find(params[:dossier_id])
|
@dossier ||= current_instructeur
|
||||||
|
.dossiers
|
||||||
|
.includes(champs: :type_de_champ)
|
||||||
|
.find(params[:dossier_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_pdf_for_instructeur_export
|
def generate_pdf_for_instructeur_export
|
||||||
|
|
|
@ -17,8 +17,6 @@ class StatsController < ApplicationController
|
||||||
stat.dossiers_deposes_entre_60_et_30_jours
|
stat.dossiers_deposes_entre_60_et_30_jours
|
||||||
)
|
)
|
||||||
|
|
||||||
@satisfaction_usagers = satisfaction_usagers
|
|
||||||
|
|
||||||
@contact_percentage = contact_percentage
|
@contact_percentage = contact_percentage
|
||||||
|
|
||||||
@dossiers_states_for_pie = {
|
@dossiers_states_for_pie = {
|
||||||
|
@ -123,42 +121,6 @@ class StatsController < ApplicationController
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def satisfaction_usagers
|
|
||||||
legend = {
|
|
||||||
Feedback.ratings.fetch(:unhappy) => "Mécontents",
|
|
||||||
Feedback.ratings.fetch(:neutral) => "Neutres",
|
|
||||||
Feedback.ratings.fetch(:happy) => "Satisfaits"
|
|
||||||
}
|
|
||||||
|
|
||||||
number_of_weeks = 12
|
|
||||||
totals = Feedback
|
|
||||||
.group_by_week(:created_at, last: number_of_weeks, current: false)
|
|
||||||
.count
|
|
||||||
|
|
||||||
legend.keys.map do |rating|
|
|
||||||
data = Feedback
|
|
||||||
.where(rating: rating)
|
|
||||||
.group_by_week(:created_at, last: number_of_weeks, current: false)
|
|
||||||
.count
|
|
||||||
.map do |week, count|
|
|
||||||
total = totals[week]
|
|
||||||
# By default a week is displayed by the first day of the week – but we'd rather display the last day
|
|
||||||
label = week.next_week
|
|
||||||
|
|
||||||
if total > 0
|
|
||||||
[label, (count.to_f / total * 100).round(2)]
|
|
||||||
else
|
|
||||||
[label, 0]
|
|
||||||
end
|
|
||||||
end.to_h
|
|
||||||
|
|
||||||
{
|
|
||||||
name: legend[rating],
|
|
||||||
data: data
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def contact_percentage
|
def contact_percentage
|
||||||
number_of_months = 13
|
number_of_months = 13
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
module Users
|
|
||||||
class FeedbacksController < UserController
|
|
||||||
def create
|
|
||||||
current_user.feedbacks.create!(rating: params[:rating])
|
|
||||||
flash.notice = "Merci de votre retour, si vous souhaitez nous en dire plus, n'hésitez pas à #{helpers.contact_link('nous contacter', type: Helpscout::FormAdapter::TYPE_AMELIORATION)}."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -77,4 +77,22 @@ class Users::SessionsController < Devise::SessionsController
|
||||||
redirect_to link_sent_path(email: instructeur.email)
|
redirect_to link_sent_path(email: instructeur.email)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def handle_unverified_request
|
||||||
|
log_invalid_authenticity_token_error
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_invalid_authenticity_token_error
|
||||||
|
Sentry.with_scope do |temp_scope|
|
||||||
|
tags = {
|
||||||
|
request_tokens: request_authenticity_tokens.compact.map { |t| t.gsub(/.....$/, '*****') }.join(', '),
|
||||||
|
session_token: session[:_csrf_token]&.gsub(/.....$/, '*****')
|
||||||
|
}
|
||||||
|
temp_scope.set_tags(tags)
|
||||||
|
Sentry.capture_message("ActionController::InvalidAuthenticityToken in Users::SessionsController")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -80,10 +80,10 @@ module Types
|
||||||
def messages(id: nil)
|
def messages(id: nil)
|
||||||
if id.present?
|
if id.present?
|
||||||
Loaders::Record
|
Loaders::Record
|
||||||
.for(Commentaire, where: { dossier: object }, includes: [:instructeur, :user], array: true)
|
.for(Commentaire, where: { dossier: object }, includes: [:instructeur, :expert], array: true)
|
||||||
.load(ApplicationRecord.id_from_typed_id(id))
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
else
|
else
|
||||||
Loaders::Association.for(object.class, commentaires: [:instructeur, :user]).load(object)
|
Loaders::Association.for(object.class, commentaires: [:instructeur, :expert]).load(object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ class Champ < ApplicationRecord
|
||||||
belongs_to :dossier, -> { with_discarded }, inverse_of: false, touch: true, optional: false
|
belongs_to :dossier, -> { with_discarded }, inverse_of: false, touch: true, optional: false
|
||||||
belongs_to :type_de_champ, inverse_of: :champ, optional: false
|
belongs_to :type_de_champ, inverse_of: :champ, optional: false
|
||||||
belongs_to :parent, class_name: 'Champ', optional: true
|
belongs_to :parent, class_name: 'Champ', optional: true
|
||||||
has_many :commentaires
|
|
||||||
has_one_attached :piece_justificative_file
|
has_one_attached :piece_justificative_file
|
||||||
|
|
||||||
# We declare champ specific relationships (Champs::CarteChamp, Champs::SiretChamp and Champs::RepetitionChamp)
|
# We declare champ specific relationships (Champs::CarteChamp, Champs::SiretChamp and Champs::RepetitionChamp)
|
||||||
|
|
|
@ -8,14 +8,15 @@
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# dossier_id :integer
|
# dossier_id :integer
|
||||||
|
# expert_id :bigint
|
||||||
# instructeur_id :bigint
|
# instructeur_id :bigint
|
||||||
# user_id :bigint
|
|
||||||
#
|
#
|
||||||
class Commentaire < ApplicationRecord
|
class Commentaire < ApplicationRecord
|
||||||
|
self.ignored_columns = [:user_id]
|
||||||
belongs_to :dossier, inverse_of: :commentaires, touch: true, optional: false
|
belongs_to :dossier, inverse_of: :commentaires, touch: true, optional: false
|
||||||
|
|
||||||
belongs_to :user, optional: true
|
|
||||||
belongs_to :instructeur, optional: true
|
belongs_to :instructeur, optional: true
|
||||||
|
belongs_to :expert, optional: true
|
||||||
|
|
||||||
validate :messagerie_available?, on: :create
|
validate :messagerie_available?, on: :create
|
||||||
|
|
||||||
|
@ -33,10 +34,10 @@ class Commentaire < ApplicationRecord
|
||||||
after_create :notify
|
after_create :notify
|
||||||
|
|
||||||
def email
|
def email
|
||||||
if user
|
if sent_by_instructeur?
|
||||||
user.email
|
|
||||||
elsif instructeur
|
|
||||||
instructeur.email
|
instructeur.email
|
||||||
|
elsif sent_by_expert?
|
||||||
|
expert.email
|
||||||
else
|
else
|
||||||
read_attribute(:email)
|
read_attribute(:email)
|
||||||
end
|
end
|
||||||
|
@ -47,7 +48,7 @@ class Commentaire < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def redacted_email
|
def redacted_email
|
||||||
if instructeur.present?
|
if sent_by_instructeur?
|
||||||
if Flipper.enabled?(:hide_instructeur_email, dossier.procedure)
|
if Flipper.enabled?(:hide_instructeur_email, dossier.procedure)
|
||||||
"Instructeur n° #{instructeur.id}"
|
"Instructeur n° #{instructeur.id}"
|
||||||
else
|
else
|
||||||
|
@ -59,8 +60,15 @@ class Commentaire < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def sent_by_system?
|
def sent_by_system?
|
||||||
[CONTACT_EMAIL, OLD_CONTACT_EMAIL].include?(email) &&
|
[CONTACT_EMAIL, OLD_CONTACT_EMAIL].include?(email)
|
||||||
user.nil? && instructeur.nil?
|
end
|
||||||
|
|
||||||
|
def sent_by_instructeur?
|
||||||
|
instructeur_id.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def sent_by_expert?
|
||||||
|
expert_id.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def sent_by?(someone)
|
def sent_by?(someone)
|
||||||
|
@ -76,15 +84,12 @@ class Commentaire < ApplicationRecord
|
||||||
private
|
private
|
||||||
|
|
||||||
def notify
|
def notify
|
||||||
dossier_user_email = dossier.user.email
|
|
||||||
invited_users_emails = dossier.invites.pluck(:email).to_a
|
|
||||||
|
|
||||||
# - If the email is the contact email, the commentaire is a copy
|
# - If the email is the contact email, the commentaire is a copy
|
||||||
# of an automated notification email we sent to a user, so do nothing.
|
# of an automated notification email we sent to a user, so do nothing.
|
||||||
# - If a user or an invited user posted a commentaire, do nothing,
|
# - If a user or an invited user posted a commentaire, do nothing,
|
||||||
# the notification system will properly
|
# the notification system will properly
|
||||||
# - Otherwise, a instructeur posted a commentaire, we need to notify the user
|
# - Otherwise, a instructeur posted a commentaire, we need to notify the user
|
||||||
if !email.in?([CONTACT_EMAIL, dossier_user_email, *invited_users_emails])
|
if sent_by_instructeur? || sent_by_expert?
|
||||||
notify_user
|
notify_user
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
# == Schema Information
|
|
||||||
#
|
|
||||||
# Table name: feedbacks
|
|
||||||
#
|
|
||||||
# id :bigint not null, primary key
|
|
||||||
# rating :string not null
|
|
||||||
# created_at :datetime not null
|
|
||||||
# updated_at :datetime not null
|
|
||||||
# user_id :bigint
|
|
||||||
#
|
|
||||||
class Feedback < ApplicationRecord
|
|
||||||
belongs_to :user, optional: false
|
|
||||||
|
|
||||||
enum rating: {
|
|
||||||
happy: 'happy',
|
|
||||||
neutral: 'neutral',
|
|
||||||
unhappy: 'unhappy'
|
|
||||||
}
|
|
||||||
|
|
||||||
validates :rating, presence: true
|
|
||||||
end
|
|
|
@ -19,8 +19,8 @@
|
||||||
# duree_conservation_dossiers_hors_ds :integer
|
# duree_conservation_dossiers_hors_ds :integer
|
||||||
# durees_conservation_required :boolean default(TRUE)
|
# durees_conservation_required :boolean default(TRUE)
|
||||||
# euro_flag :boolean default(FALSE)
|
# euro_flag :boolean default(FALSE)
|
||||||
# for_individual :boolean default(FALSE)
|
|
||||||
# experts_require_administrateur_invitation :boolean default(FALSE)
|
# experts_require_administrateur_invitation :boolean default(FALSE)
|
||||||
|
# for_individual :boolean default(FALSE)
|
||||||
# hidden_at :datetime
|
# hidden_at :datetime
|
||||||
# juridique_required :boolean default(TRUE)
|
# juridique_required :boolean default(TRUE)
|
||||||
# libelle :string
|
# libelle :string
|
||||||
|
|
|
@ -44,7 +44,6 @@ class User < ApplicationRecord
|
||||||
has_many :dossiers, dependent: :destroy
|
has_many :dossiers, dependent: :destroy
|
||||||
has_many :invites, dependent: :destroy
|
has_many :invites, dependent: :destroy
|
||||||
has_many :dossiers_invites, through: :invites, source: :dossier
|
has_many :dossiers_invites, through: :invites, source: :dossier
|
||||||
has_many :feedbacks, dependent: :destroy
|
|
||||||
has_many :deleted_dossiers
|
has_many :deleted_dossiers
|
||||||
has_one :france_connect_information, dependent: :destroy
|
has_one :france_connect_information, dependent: :destroy
|
||||||
belongs_to :instructeur, optional: true
|
belongs_to :instructeur, optional: true
|
||||||
|
|
|
@ -2,10 +2,10 @@ class CommentaireService
|
||||||
class << self
|
class << self
|
||||||
def build(sender, dossier, params)
|
def build(sender, dossier, params)
|
||||||
case sender
|
case sender
|
||||||
when User
|
|
||||||
params[:user] = sender
|
|
||||||
when Instructeur
|
when Instructeur
|
||||||
params[:instructeur] = sender
|
params[:instructeur] = sender
|
||||||
|
when Expert
|
||||||
|
params[:expert] = sender
|
||||||
end
|
end
|
||||||
|
|
||||||
build_with_email(sender.email, dossier, params)
|
build_with_email(sender.email, dossier, params)
|
||||||
|
|
|
@ -24,19 +24,6 @@
|
||||||
%span.big-number-card-detail
|
%span.big-number-card-detail
|
||||||
#{number_with_delimiter(@dossiers_numbers[:last_30_days_count])} (#{@dossiers_numbers[:evolution]} %) sur les 30 derniers jours
|
#{number_with_delimiter(@dossiers_numbers[:last_30_days_count])} (#{@dossiers_numbers[:evolution]} %) sur les 30 derniers jours
|
||||||
|
|
||||||
.stat-card.stat-card-half.pull-left
|
|
||||||
%span.stat-card-title
|
|
||||||
Satisfaction usager
|
|
||||||
|
|
||||||
.chart-container
|
|
||||||
.chart
|
|
||||||
= area_chart @satisfaction_usagers,
|
|
||||||
stacked: true,
|
|
||||||
suffix: ' %',
|
|
||||||
max: 100,
|
|
||||||
library: { plotOptions: { series: { marker: { enabled: true }}}},
|
|
||||||
colors: ["#C31C25", "#F5962A", "#25B177"]
|
|
||||||
|
|
||||||
.stat-card.stat-card-half.pull-left
|
.stat-card.stat-card-half.pull-left
|
||||||
%span.stat-card-title
|
%span.stat-card-title
|
||||||
Pourcentage de contact utilisateur
|
Pourcentage de contact utilisateur
|
||||||
|
|
|
@ -23,17 +23,6 @@
|
||||||
|
|
||||||
= paginate(deleted_dossiers)
|
= paginate(deleted_dossiers)
|
||||||
|
|
||||||
- if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago
|
|
||||||
#user-satisfaction
|
|
||||||
%h3 Que pensez-vous de la facilité d'utilisation de ce service ?
|
|
||||||
.icons
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:unhappy)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.frown
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:neutral)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.meh
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:happy)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.smile
|
|
||||||
|
|
||||||
- else
|
- else
|
||||||
.blank-tab
|
.blank-tab
|
||||||
%h2.empty-text Aucun dossier.
|
%h2.empty-text Aucun dossier.
|
||||||
|
|
|
@ -31,17 +31,6 @@
|
||||||
|
|
||||||
= paginate(dossiers)
|
= paginate(dossiers)
|
||||||
|
|
||||||
- if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago
|
|
||||||
#user-satisfaction
|
|
||||||
%h3 Que pensez-vous de la facilité d'utilisation de ce service ?
|
|
||||||
.icons
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:unhappy)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.frown
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:neutral)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.meh
|
|
||||||
= link_to feedback_path(rating: Feedback.ratings.fetch(:happy)), data: { remote: true, method: :post } do
|
|
||||||
%span.icon.smile
|
|
||||||
|
|
||||||
- else
|
- else
|
||||||
.blank-tab
|
.blank-tab
|
||||||
%h2.empty-text Aucun dossier.
|
%h2.empty-text Aucun dossier.
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
try {
|
|
||||||
window.scroll({ top: 0, left: 0, behavior: 'smooth' });
|
|
||||||
} catch(e) {
|
|
||||||
window.scroll(0, 0);
|
|
||||||
}
|
|
||||||
<%= remove_element('#user-satisfaction') %>
|
|
||||||
<%= render_flash %>
|
|
|
@ -11,7 +11,7 @@
|
||||||
%p
|
%p
|
||||||
Ouvrez votre boite email <strong>#{@email}</strong> puis cliquez sur le lien d’activation du message <strong>Connexion sécurisée à #{APPLICATION_NAME}</strong>.
|
Ouvrez votre boite email <strong>#{@email}</strong> puis cliquez sur le lien d’activation du message <strong>Connexion sécurisée à #{APPLICATION_NAME}</strong>.
|
||||||
%p
|
%p
|
||||||
= t('views.users.shared.email_can_take_a_while')
|
= t('views.users.shared.email_can_take_a_while_html')
|
||||||
|
|
||||||
%section.link-sent-help
|
%section.link-sent-help
|
||||||
%p
|
%p
|
||||||
|
|
|
@ -58,10 +58,10 @@ fr:
|
||||||
reset_link_sent:
|
reset_link_sent:
|
||||||
email_sent_html: "Nous vous avons envoyé un email à l’adresse <strong>%{email}</strong>."
|
email_sent_html: "Nous vous avons envoyé un email à l’adresse <strong>%{email}</strong>."
|
||||||
click_link_to_reset_password: "Cliquez sur le lien contenu dans l’email pour changer votre mot de passe."
|
click_link_to_reset_password: "Cliquez sur le lien contenu dans l’email pour changer votre mot de passe."
|
||||||
no_mail: "Vous n’avez pas reçu l’email ?"
|
no_mail: "Vous n’avez pas reçu l’email ?"
|
||||||
check_spams: "Vérifiez la boite Indésirables ou Spam de votre boite email."
|
check_spams: "Vérifiez la boite Indésirables ou Spam de votre boite email."
|
||||||
check_account: "Avez-vous bien créé un compte %{application_name} avec l’adresse %{email} ? Si aucun compte n’existe avec cette adresse, vous ne recevrez pas de message."
|
check_account: "Avez-vous bien créé un compte %{application_name} avec l’adresse %{email} ? Si aucun compte n’existe avec cette adresse, vous ne recevrez pas de message."
|
||||||
check_france_connect_html: "Vous êtes-vous connecté avec France Connect par le passé ? Dans ce cas <a href=\"%{href}\">essayez à nouveau avec France Connect</a>."
|
check_france_connect_html: "Vous êtes-vous connecté avec France Connect par le passé ? Dans ce cas <a href=\"%{href}\">essayez à nouveau avec France Connect</a>."
|
||||||
got_it: "Bien reçu !"
|
got_it: "Bien reçu !"
|
||||||
open_your_mailbox: "Maintenant ouvrez votre boite email."
|
open_your_mailbox: "Maintenant ouvrez votre boite email."
|
||||||
title: "Lien de réinitialisation du mot de passe envoyé"
|
title: "Lien de réinitialisation du mot de passe envoyé"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddExpertIdToCommentaires < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_belongs_to :commentaires, :expert, type: :bigint, foreign_key: true
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20210427120000_add_unique_index_to_invites.rb
Normal file
14
db/migrate/20210427120000_add_unique_index_to_invites.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class AddUniqueIndexToInvites < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :invites, [:email, :dossier_id]
|
||||||
|
add_concurrent_index :invites, [:email, :dossier_id], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :invites, column: [:email, :dossier_id]
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20210427120001_add_unique_index_to_procedures.rb
Normal file
14
db/migrate/20210427120001_add_unique_index_to_procedures.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class AddUniqueIndexToProcedures < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :procedures, [:path, :closed_at, :hidden_at, :unpublished_at]
|
||||||
|
add_concurrent_index :procedures, [:path, :closed_at, :hidden_at, :unpublished_at], name: 'procedure_path_uniqueness', unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :procedures, [:path, :closed_at, :hidden_at, :unpublished_at], name: 'procedure_path_uniqueness'
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20210427120002_add_unique_index_to_individuals.rb
Normal file
14
db/migrate/20210427120002_add_unique_index_to_individuals.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class AddUniqueIndexToIndividuals < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :individuals, [:dossier_id]
|
||||||
|
add_concurrent_index :individuals, [:dossier_id], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :individuals, [:dossier_id]
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
ActiveRecord::Schema.define(version: 2021_04_27_120002) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -175,7 +175,9 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.bigint "user_id"
|
t.bigint "user_id"
|
||||||
t.bigint "instructeur_id"
|
t.bigint "instructeur_id"
|
||||||
|
t.bigint "expert_id"
|
||||||
t.index ["dossier_id"], name: "index_commentaires_on_dossier_id"
|
t.index ["dossier_id"], name: "index_commentaires_on_dossier_id"
|
||||||
|
t.index ["expert_id"], name: "index_commentaires_on_expert_id"
|
||||||
t.index ["instructeur_id"], name: "index_commentaires_on_instructeur_id"
|
t.index ["instructeur_id"], name: "index_commentaires_on_instructeur_id"
|
||||||
t.index ["user_id"], name: "index_commentaires_on_user_id"
|
t.index ["user_id"], name: "index_commentaires_on_user_id"
|
||||||
end
|
end
|
||||||
|
@ -444,7 +446,7 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.date "birthdate"
|
t.date "birthdate"
|
||||||
t.index ["dossier_id"], name: "index_individuals_on_dossier_id"
|
t.index ["dossier_id"], name: "index_individuals_on_dossier_id", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "initiated_mails", id: :serial, force: :cascade do |t|
|
create_table "initiated_mails", id: :serial, force: :cascade do |t|
|
||||||
|
@ -472,6 +474,7 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.text "message"
|
t.text "message"
|
||||||
|
t.index ["email", "dossier_id"], name: "index_invites_on_email_and_dossier_id", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "module_api_cartos", id: :serial, force: :cascade do |t|
|
create_table "module_api_cartos", id: :serial, force: :cascade do |t|
|
||||||
|
@ -557,6 +560,7 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
||||||
t.index ["draft_revision_id"], name: "index_procedures_on_draft_revision_id"
|
t.index ["draft_revision_id"], name: "index_procedures_on_draft_revision_id"
|
||||||
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
||||||
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
||||||
|
t.index ["path", "closed_at", "hidden_at", "unpublished_at"], name: "procedure_path_uniqueness", unique: true
|
||||||
t.index ["path", "closed_at", "hidden_at"], name: "index_procedures_on_path_and_closed_at_and_hidden_at", unique: true
|
t.index ["path", "closed_at", "hidden_at"], name: "index_procedures_on_path_and_closed_at_and_hidden_at", unique: true
|
||||||
t.index ["published_revision_id"], name: "index_procedures_on_published_revision_id"
|
t.index ["published_revision_id"], name: "index_procedures_on_published_revision_id"
|
||||||
t.index ["service_id"], name: "index_procedures_on_service_id"
|
t.index ["service_id"], name: "index_procedures_on_service_id"
|
||||||
|
@ -738,6 +742,7 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
||||||
add_foreign_key "champs", "champs", column: "parent_id"
|
add_foreign_key "champs", "champs", column: "parent_id"
|
||||||
add_foreign_key "closed_mails", "procedures"
|
add_foreign_key "closed_mails", "procedures"
|
||||||
add_foreign_key "commentaires", "dossiers"
|
add_foreign_key "commentaires", "dossiers"
|
||||||
|
add_foreign_key "commentaires", "experts"
|
||||||
add_foreign_key "dossier_operation_logs", "bill_signatures"
|
add_foreign_key "dossier_operation_logs", "bill_signatures"
|
||||||
add_foreign_key "dossier_operation_logs", "instructeurs"
|
add_foreign_key "dossier_operation_logs", "instructeurs"
|
||||||
add_foreign_key "dossiers", "groupe_instructeurs"
|
add_foreign_key "dossiers", "groupe_instructeurs"
|
||||||
|
|
|
@ -185,60 +185,6 @@ describe StatsController, type: :controller do
|
||||||
it { expect(subject).to eq(@expected_hash) }
|
it { expect(subject).to eq(@expected_hash) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#satisfaction_usagers" do
|
|
||||||
before do
|
|
||||||
# Test the stats on October 2018 – where the 1st, 8th, 15th, 22th and 29th are conveniently Mondays
|
|
||||||
# Current week: 1 negative feedback
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 22, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
# Last week: 3 positive, 1 negative
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 21, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 19, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 17, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 15, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
# N-2 week: 2 positive, 2 negative
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 14, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 12, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 10, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 8, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
# N-3 week: 1 positive, 3 negative
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 1, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 3, 12, 00)) { create(:feedback, :happy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 5, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 7, 12, 00)) { create(:feedback, :unhappy) }
|
|
||||||
end
|
|
||||||
|
|
||||||
subject(:stats) do
|
|
||||||
Timecop.freeze(Time.zone.local(2018, 10, 28, 12, 00)) {
|
|
||||||
StatsController.new.send(:satisfaction_usagers)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns one set of values for each kind of feedback' do
|
|
||||||
expect(stats.count).to eq 3
|
|
||||||
expect(stats.map { |g| g[:name] }).to contain_exactly('Satisfaits', 'Neutres', 'Mécontents')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns weekly ratios between a given feedback and all feedback' do
|
|
||||||
happy_data = stats.find { |g| g[:name] == 'Satisfaits' }[:data]
|
|
||||||
|
|
||||||
expect(happy_data.values[-4]).to eq 0
|
|
||||||
expect(happy_data.values[-3]).to eq 25.0
|
|
||||||
expect(happy_data.values[-2]).to eq 50.0
|
|
||||||
expect(happy_data.values[-1]).to eq 75.0
|
|
||||||
|
|
||||||
unhappy_data = stats.find { |g| g[:name] == 'Mécontents' }[:data]
|
|
||||||
expect(unhappy_data.values[-4]).to eq 0
|
|
||||||
expect(unhappy_data.values[-3]).to eq 75.0
|
|
||||||
expect(unhappy_data.values[-2]).to eq 50.0
|
|
||||||
expect(unhappy_data.values[-1]).to eq 25.0
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'excludes values still in the current week' do
|
|
||||||
unhappy_data = stats.find { |g| g[:name] == 'Mécontents' }[:data]
|
|
||||||
expect(unhappy_data.values).not_to include(100.0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#avis_usage' do
|
describe '#avis_usage' do
|
||||||
let!(:dossier) { create(:dossier) }
|
let!(:dossier) { create(:dossier) }
|
||||||
let!(:avis_with_dossier) { create(:avis) }
|
let!(:avis_with_dossier) { create(:avis) }
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :feedback do
|
|
||||||
rating { Feedback.ratings.fetch(:happy) }
|
|
||||||
association :user
|
|
||||||
|
|
||||||
trait :happy do
|
|
||||||
rating { Feedback.ratings.fetch(:happy) }
|
|
||||||
end
|
|
||||||
|
|
||||||
trait :neutral do
|
|
||||||
rating { Feedback.ratings.fetch(:neutral) }
|
|
||||||
end
|
|
||||||
|
|
||||||
trait :unhappy do
|
|
||||||
rating { Feedback.ratings.fetch(:unhappy) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -63,7 +63,7 @@ describe Commentaire do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a commentaire created by a user' do
|
context 'with a commentaire created by a user' do
|
||||||
let(:commentaire) { build :commentaire, user: user }
|
let(:commentaire) { build :commentaire, email: user.email }
|
||||||
let(:user) { build :user, email: 'some_user@exemple.fr' }
|
let(:user) { build :user, email: 'some_user@exemple.fr' }
|
||||||
|
|
||||||
it { is_expected.to eq 'some_user@exemple.fr' }
|
it { is_expected.to eq 'some_user@exemple.fr' }
|
||||||
|
@ -73,26 +73,34 @@ describe Commentaire do
|
||||||
describe "#notify" do
|
describe "#notify" do
|
||||||
let(:procedure) { create(:procedure) }
|
let(:procedure) { create(:procedure) }
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
let(:expert) { create(:expert) }
|
||||||
let(:assign_to) { create(:assign_to, instructeur: instructeur, procedure: procedure) }
|
let(:assign_to) { create(:assign_to, instructeur: instructeur, procedure: procedure) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure, user: user) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure, user: user) }
|
||||||
let(:commentaire) { Commentaire.new(dossier: dossier, body: "Mon commentaire") }
|
|
||||||
|
|
||||||
context "with a commentaire created by a instructeur" do
|
context "with a commentaire created by a instructeur" do
|
||||||
|
let(:commentaire) { CommentaireService.build(instructeur, dossier, body: "Mon commentaire") }
|
||||||
|
|
||||||
it "calls notify_user" do
|
it "calls notify_user" do
|
||||||
expect(commentaire).to receive(:notify_user)
|
expect(commentaire).to receive(:notify_user)
|
||||||
|
commentaire.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
commentaire.email = instructeur.email
|
context "with a commentaire created by an expert" do
|
||||||
|
let(:commentaire) { CommentaireService.build(expert, dossier, body: "Mon commentaire") }
|
||||||
|
|
||||||
|
it "calls notify_user" do
|
||||||
|
expect(commentaire).to receive(:notify_user)
|
||||||
commentaire.save
|
commentaire.save
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a commentaire automatically created (notification)" do
|
context "with a commentaire automatically created (notification)" do
|
||||||
it "does not call notify_user or notify_instructeurs" do
|
let(:commentaire) { CommentaireService.build_with_email(CONTACT_EMAIL, dossier, body: "Mon commentaire") }
|
||||||
expect(commentaire).not_to receive(:notify_user)
|
|
||||||
expect(commentaire).not_to receive(:notify_instructeurs)
|
|
||||||
|
|
||||||
commentaire.email = CONTACT_EMAIL
|
it "does not call notify_user" do
|
||||||
|
expect(commentaire).not_to receive(:notify_user)
|
||||||
commentaire.save
|
commentaire.save
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -69,17 +69,4 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
||||||
expect(rendered).to have_selector('ul.tabs li.active', count: 1)
|
expect(rendered).to have_selector('ul.tabs li.active', count: 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "quand le user n'a aucun feedback" do
|
|
||||||
it "affiche le formulaire de satisfaction" do
|
|
||||||
expect(rendered).to have_selector('#user-satisfaction', text: 'Que pensez-vous de la facilité d\'utilisation de ce service ?')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "quand le user a un feedback" do
|
|
||||||
let(:user) { create(:user, feedbacks: [build(:feedback)]) }
|
|
||||||
it "n'affiche pas le formulaire de satisfaction" do
|
|
||||||
expect(rendered).to_not have_selector('#user-satisfaction')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue