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
|
||||
|
||||
def dossier
|
||||
@dossier ||= current_instructeur.dossiers.find(params[:dossier_id])
|
||||
@dossier ||= current_instructeur
|
||||
.dossiers
|
||||
.includes(champs: :type_de_champ)
|
||||
.find(params[:dossier_id])
|
||||
end
|
||||
|
||||
def generate_pdf_for_instructeur_export
|
||||
|
|
|
@ -17,8 +17,6 @@ class StatsController < ApplicationController
|
|||
stat.dossiers_deposes_entre_60_et_30_jours
|
||||
)
|
||||
|
||||
@satisfaction_usagers = satisfaction_usagers
|
||||
|
||||
@contact_percentage = contact_percentage
|
||||
|
||||
@dossiers_states_for_pie = {
|
||||
|
@ -123,42 +121,6 @@ class StatsController < ApplicationController
|
|||
}
|
||||
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
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -80,10 +80,10 @@ module Types
|
|||
def messages(id: nil)
|
||||
if id.present?
|
||||
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))
|
||||
else
|
||||
Loaders::Association.for(object.class, commentaires: [:instructeur, :user]).load(object)
|
||||
Loaders::Association.for(object.class, commentaires: [:instructeur, :expert]).load(object)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ class Champ < ApplicationRecord
|
|||
belongs_to :dossier, -> { with_discarded }, inverse_of: false, touch: true, optional: false
|
||||
belongs_to :type_de_champ, inverse_of: :champ, optional: false
|
||||
belongs_to :parent, class_name: 'Champ', optional: true
|
||||
has_many :commentaires
|
||||
has_one_attached :piece_justificative_file
|
||||
|
||||
# We declare champ specific relationships (Champs::CarteChamp, Champs::SiretChamp and Champs::RepetitionChamp)
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# dossier_id :integer
|
||||
# expert_id :bigint
|
||||
# instructeur_id :bigint
|
||||
# user_id :bigint
|
||||
#
|
||||
class Commentaire < ApplicationRecord
|
||||
self.ignored_columns = [:user_id]
|
||||
belongs_to :dossier, inverse_of: :commentaires, touch: true, optional: false
|
||||
|
||||
belongs_to :user, optional: true
|
||||
belongs_to :instructeur, optional: true
|
||||
belongs_to :expert, optional: true
|
||||
|
||||
validate :messagerie_available?, on: :create
|
||||
|
||||
|
@ -33,10 +34,10 @@ class Commentaire < ApplicationRecord
|
|||
after_create :notify
|
||||
|
||||
def email
|
||||
if user
|
||||
user.email
|
||||
elsif instructeur
|
||||
if sent_by_instructeur?
|
||||
instructeur.email
|
||||
elsif sent_by_expert?
|
||||
expert.email
|
||||
else
|
||||
read_attribute(:email)
|
||||
end
|
||||
|
@ -47,7 +48,7 @@ class Commentaire < ApplicationRecord
|
|||
end
|
||||
|
||||
def redacted_email
|
||||
if instructeur.present?
|
||||
if sent_by_instructeur?
|
||||
if Flipper.enabled?(:hide_instructeur_email, dossier.procedure)
|
||||
"Instructeur n° #{instructeur.id}"
|
||||
else
|
||||
|
@ -59,8 +60,15 @@ class Commentaire < ApplicationRecord
|
|||
end
|
||||
|
||||
def sent_by_system?
|
||||
[CONTACT_EMAIL, OLD_CONTACT_EMAIL].include?(email) &&
|
||||
user.nil? && instructeur.nil?
|
||||
[CONTACT_EMAIL, OLD_CONTACT_EMAIL].include?(email)
|
||||
end
|
||||
|
||||
def sent_by_instructeur?
|
||||
instructeur_id.present?
|
||||
end
|
||||
|
||||
def sent_by_expert?
|
||||
expert_id.present?
|
||||
end
|
||||
|
||||
def sent_by?(someone)
|
||||
|
@ -76,15 +84,12 @@ class Commentaire < ApplicationRecord
|
|||
private
|
||||
|
||||
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
|
||||
# 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,
|
||||
# the notification system will properly
|
||||
# - 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
|
||||
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
|
|
@ -2,47 +2,47 @@
|
|||
#
|
||||
# Table name: procedures
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# aasm_state :string default("brouillon")
|
||||
# allow_expert_review :boolean default(TRUE), not null
|
||||
# api_entreprise_token :string
|
||||
# ask_birthday :boolean default(FALSE), not null
|
||||
# auto_archive_on :date
|
||||
# cadre_juridique :string
|
||||
# cerfa_flag :boolean default(FALSE)
|
||||
# cloned_from_library :boolean default(FALSE)
|
||||
# closed_at :datetime
|
||||
# declarative_with_state :string
|
||||
# description :string
|
||||
# direction :string
|
||||
# duree_conservation_dossiers_dans_ds :integer
|
||||
# duree_conservation_dossiers_hors_ds :integer
|
||||
# durees_conservation_required :boolean default(TRUE)
|
||||
# euro_flag :boolean default(FALSE)
|
||||
# for_individual :boolean default(FALSE)
|
||||
# id :integer not null, primary key
|
||||
# aasm_state :string default("brouillon")
|
||||
# allow_expert_review :boolean default(TRUE), not null
|
||||
# api_entreprise_token :string
|
||||
# ask_birthday :boolean default(FALSE), not null
|
||||
# auto_archive_on :date
|
||||
# cadre_juridique :string
|
||||
# cerfa_flag :boolean default(FALSE)
|
||||
# cloned_from_library :boolean default(FALSE)
|
||||
# closed_at :datetime
|
||||
# declarative_with_state :string
|
||||
# description :string
|
||||
# direction :string
|
||||
# duree_conservation_dossiers_dans_ds :integer
|
||||
# duree_conservation_dossiers_hors_ds :integer
|
||||
# durees_conservation_required :boolean default(TRUE)
|
||||
# euro_flag :boolean default(FALSE)
|
||||
# experts_require_administrateur_invitation :boolean default(FALSE)
|
||||
# hidden_at :datetime
|
||||
# juridique_required :boolean default(TRUE)
|
||||
# libelle :string
|
||||
# lien_demarche :string
|
||||
# lien_notice :string
|
||||
# lien_site_web :string
|
||||
# monavis_embed :text
|
||||
# organisation :string
|
||||
# path :string not null
|
||||
# published_at :datetime
|
||||
# routing_criteria_name :text default("Votre ville")
|
||||
# test_started_at :datetime
|
||||
# unpublished_at :datetime
|
||||
# web_hook_url :string
|
||||
# whitelisted_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# canonical_procedure_id :bigint
|
||||
# draft_revision_id :bigint
|
||||
# parent_procedure_id :bigint
|
||||
# published_revision_id :bigint
|
||||
# service_id :bigint
|
||||
# for_individual :boolean default(FALSE)
|
||||
# hidden_at :datetime
|
||||
# juridique_required :boolean default(TRUE)
|
||||
# libelle :string
|
||||
# lien_demarche :string
|
||||
# lien_notice :string
|
||||
# lien_site_web :string
|
||||
# monavis_embed :text
|
||||
# organisation :string
|
||||
# path :string not null
|
||||
# published_at :datetime
|
||||
# routing_criteria_name :text default("Votre ville")
|
||||
# test_started_at :datetime
|
||||
# unpublished_at :datetime
|
||||
# web_hook_url :string
|
||||
# whitelisted_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# canonical_procedure_id :bigint
|
||||
# draft_revision_id :bigint
|
||||
# parent_procedure_id :bigint
|
||||
# published_revision_id :bigint
|
||||
# service_id :bigint
|
||||
#
|
||||
|
||||
class Procedure < ApplicationRecord
|
||||
|
|
|
@ -44,7 +44,6 @@ class User < ApplicationRecord
|
|||
has_many :dossiers, dependent: :destroy
|
||||
has_many :invites, dependent: :destroy
|
||||
has_many :dossiers_invites, through: :invites, source: :dossier
|
||||
has_many :feedbacks, dependent: :destroy
|
||||
has_many :deleted_dossiers
|
||||
has_one :france_connect_information, dependent: :destroy
|
||||
belongs_to :instructeur, optional: true
|
||||
|
|
|
@ -2,10 +2,10 @@ class CommentaireService
|
|||
class << self
|
||||
def build(sender, dossier, params)
|
||||
case sender
|
||||
when User
|
||||
params[:user] = sender
|
||||
when Instructeur
|
||||
params[:instructeur] = sender
|
||||
when Expert
|
||||
params[:expert] = sender
|
||||
end
|
||||
|
||||
build_with_email(sender.email, dossier, params)
|
||||
|
|
|
@ -24,19 +24,6 @@
|
|||
%span.big-number-card-detail
|
||||
#{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
|
||||
%span.stat-card-title
|
||||
Pourcentage de contact utilisateur
|
||||
|
|
|
@ -23,17 +23,6 @@
|
|||
|
||||
= 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
|
||||
.blank-tab
|
||||
%h2.empty-text Aucun dossier.
|
||||
|
|
|
@ -31,17 +31,6 @@
|
|||
|
||||
= 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
|
||||
.blank-tab
|
||||
%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
|
||||
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
|
||||
= t('views.users.shared.email_can_take_a_while')
|
||||
= t('views.users.shared.email_can_take_a_while_html')
|
||||
|
||||
%section.link-sent-help
|
||||
%p
|
||||
|
|
|
@ -58,10 +58,10 @@ fr:
|
|||
reset_link_sent:
|
||||
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."
|
||||
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_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_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>."
|
||||
got_it: "Bien reçu !"
|
||||
open_your_mailbox: "Maintenant ouvrez votre boite email."
|
||||
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.
|
||||
|
||||
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
|
||||
enable_extension "plpgsql"
|
||||
|
@ -175,7 +175,9 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
|||
t.datetime "updated_at", null: false
|
||||
t.bigint "user_id"
|
||||
t.bigint "instructeur_id"
|
||||
t.bigint "expert_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 ["user_id"], name: "index_commentaires_on_user_id"
|
||||
end
|
||||
|
@ -444,7 +446,7 @@ ActiveRecord::Schema.define(version: 2021_04_16_160721) do
|
|||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
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
|
||||
|
||||
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 "updated_at"
|
||||
t.text "message"
|
||||
t.index ["email", "dossier_id"], name: "index_invites_on_email_and_dossier_id", unique: true
|
||||
end
|
||||
|
||||
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 ["hidden_at"], name: "index_procedures_on_hidden_at"
|
||||
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 ["published_revision_id"], name: "index_procedures_on_published_revision_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 "closed_mails", "procedures"
|
||||
add_foreign_key "commentaires", "dossiers"
|
||||
add_foreign_key "commentaires", "experts"
|
||||
add_foreign_key "dossier_operation_logs", "bill_signatures"
|
||||
add_foreign_key "dossier_operation_logs", "instructeurs"
|
||||
add_foreign_key "dossiers", "groupe_instructeurs"
|
||||
|
|
|
@ -185,60 +185,6 @@ describe StatsController, type: :controller do
|
|||
it { expect(subject).to eq(@expected_hash) }
|
||||
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
|
||||
let!(:dossier) { create(:dossier) }
|
||||
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
|
||||
|
||||
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' }
|
||||
|
||||
it { is_expected.to eq 'some_user@exemple.fr' }
|
||||
|
@ -73,26 +73,34 @@ describe Commentaire do
|
|||
describe "#notify" do
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:expert) { create(:expert) }
|
||||
let(:assign_to) { create(:assign_to, instructeur: instructeur, procedure: procedure) }
|
||||
let(:user) { create(: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
|
||||
let(:commentaire) { CommentaireService.build(instructeur, dossier, body: "Mon commentaire") }
|
||||
|
||||
it "calls notify_user" do
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
context "with a commentaire automatically created (notification)" do
|
||||
it "does not call notify_user or notify_instructeurs" do
|
||||
expect(commentaire).not_to receive(:notify_user)
|
||||
expect(commentaire).not_to receive(:notify_instructeurs)
|
||||
let(:commentaire) { CommentaireService.build_with_email(CONTACT_EMAIL, dossier, body: "Mon commentaire") }
|
||||
|
||||
commentaire.email = CONTACT_EMAIL
|
||||
it "does not call notify_user" do
|
||||
expect(commentaire).not_to receive(:notify_user)
|
||||
commentaire.save
|
||||
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)
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue