Skip to content

Commit

Permalink
Merge pull request #3463 from betagouv/onglet-satisfaction
Browse files Browse the repository at this point in the history
Onglet satisfaction
  • Loading branch information
clairezed authored Jun 5, 2024
2 parents b8ecd90 + 74838a2 commit 9bcbd82
Show file tree
Hide file tree
Showing 41 changed files with 645 additions and 32 deletions.
55 changes: 52 additions & 3 deletions app/admin/company_satisfaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
init_subjects_filter
end

includes :need, :landing, :solicitation, :subject, :facility
includes :need, :landing, :solicitation, :subject, :facility, :shared_satisfactions
config.sort_order = 'created_at_desc'

scope :all, default: true
Expand All @@ -22,7 +22,16 @@
selectable_column
column :contacted_by_expert
column :useful_exchange
column :comment
column :comment do |s|
div s.comment
if s.shared
br
div t('active_admin.company_satisfaction.shared_with')
s.shared_satisfaction_experts.each do |e|
admin_link_to e
end
end
end
column :need do |s|
link_to s.need.to_s, conseiller_diagnosis_path(s.need.diagnosis)
end
Expand All @@ -39,7 +48,10 @@
end

column :created_at
actions dropdown: true

actions dropdown: true do |cs|
item t('active_admin.company_satisfaction.share'), share_admin_company_satisfaction_path(cs)
end
end

filter :created_at
Expand All @@ -48,10 +60,12 @@
filter :theme, as: :select, collection: -> { Theme.order(:label).pluck(:label, :id) }
filter :subject, as: :ajax_select, collection: -> { @subjects.pluck(:label, :id) }, data: { url: :admin_subjects_path, search_fields: [:label] }
filter :done_institutions, as: :ajax_select, data: { url: :admin_institutions_path, search_fields: [:name] }
filter :experts, as: :ajax_select, data: { url: :admin_experts_path, search_fields: [:full_name] }
filter :facility, as: :ajax_select, data: { url: :admin_facilities_path, search_fields: [:name] }
filter :solicitation_email_cont
filter :facility_regions, collection: -> { Territory.regions.order(:name) }
filter :landing, as: :ajax_select, collection: -> { Landing.not_archived.pluck(:title, :id) }, data: { url: :admin_landings_path, search_fields: [:title] }
filter :shared, as: :select, collection: [["Oui", 'shared'], ["Non", 'not_shared']]

filter :solicitation_mtm_campaign, as: :string
filter :solicitation_mtm_kwd, as: :string
Expand All @@ -73,4 +87,39 @@
s.solicitation&.provenance_detail
end
end

## Show
#
show do
attributes_table do
row :created_at
row :contacted_by_expert
row :useful_exchange
row :comment
row :need
row(:shared_with) do |s|
div raw shared_satisfactions_links(s.shared_satisfactions) if s.shared_satisfactions.any?
end
end
end

## Actions
#

action_item :share, only: :show do
link_to t('active_admin.company_satisfaction.share'), { action: :share }, data: { confirm: t('active_admin.company_satisfaction.share_confirmation') }
end

member_action :share do
if resource.share
redirect_back fallback_location: collection_path, notice: t('active_admin.company_satisfaction.shared')
else
redirect_back fallback_location: collection_path, alert: resource.errors.full_messages.uniq.to_sentence
end
end

batch_action I18n.t('active_admin.company_satisfaction.share'), { action: :share, confirm: I18n.t('active_admin.company_satisfaction.share_confirmation') } do |ids|
CompanySatisfaction.where(id: ids).find_each { |s| s.share }
redirect_back fallback_location: collection_path, notice: I18n.t('active_admin.company_satisfaction.shared')
end
end
2 changes: 2 additions & 0 deletions app/admin/expert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
end
column(:activity) do |e|
div admin_link_to(e, :received_matches, blank_if_empty: true)
admin_link_to_expert_shared_satisfaction(e)
end
end

Expand Down Expand Up @@ -138,6 +139,7 @@
end
row(:activity) do |e|
div admin_link_to(e, :received_matches)
admin_link_to_expert_shared_satisfaction(e)
end

attributes_table title: I18n.t('active_admin.expert.skills') do
Expand Down
15 changes: 15 additions & 0 deletions app/admin/helpers/links.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ def diagnosis_link(diagnosis)
end
link
end

def shared_satisfactions_links(shared_satisfactions)
shared_satisfactions.map do |ss|
user = ss.user
"#{admin_link_to ss.company_satisfaction.done_experts.joins(:users).where(users: user).first} - #{admin_link_to user}"
end.join('<br/>')
end

def admin_link_to_expert_shared_satisfaction(expert)
count = expert.shared_company_satisfactions.count
if count > 0
text = "#{count} #{Expert.human_attribute_name(:shared_company_satisfactions, count: count).downcase}"
div link_to text, admin_company_satisfactions_path('q[matches_expert_id_eq]': expert.id, 'q[shared_eq]': 'shared')
end
end
end

Arbre::Element.include Links
Expand Down
61 changes: 61 additions & 0 deletions app/controllers/conseiller/shared_satisfactions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class Conseiller::SharedSatisfactionsController < ApplicationController
before_action :collections_counts

layout 'side_menu'

def index
redirect_to action: :unseen
end

def unseen
@needs = retrieve_unseen_satisfactions
.order(:created_at)
.page(params[:page])

render :index
end

def seen
@needs = retrieve_seen_satisfactions
.order(:created_at)
.page(params[:page])

render :index
end

def mark_as_seen
@shared_satisfaction = SharedSatisfaction.find(params[:id])
if @shared_satisfaction.touch(:seen_at)
flash.notice = t('conseiller.shared_satisfactions.satifaction_seen')
redirect_back_or_to(unseen_conseiller_shared_satisfactions_path)
else
flash.alert = @shared_satisfaction.errors.full_messages.to_sentence
redirect_back_or_to(unseen_conseiller_shared_satisfactions_path)
end
end

private

def retrieve_unseen_satisfactions
@unseen_satisfactions ||= current_user.received_needs
.joins(company_satisfaction: :shared_satisfactions)
.merge(SharedSatisfaction.unseen.where(user_id: current_user.id))
.distinct
end

def retrieve_seen_satisfactions
@seen_satisfactions ||= current_user.received_needs
.joins(company_satisfaction: :shared_satisfactions)
.merge(SharedSatisfaction.seen.where(user_id: current_user.id))
.distinct
end

def collections_counts
@satisfaction_collections_count = Rails.cache.fetch(['satisfaction', retrieve_unseen_satisfactions.size, retrieve_seen_satisfactions.size]) do
{
unseen: retrieve_unseen_satisfactions.size,
seen: retrieve_seen_satisfactions.size,
}
end
end
end
4 changes: 3 additions & 1 deletion app/front/stylesheets/application/custom_components.sass
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.count-notification
background-color: $orange
color: $white
min-width: 0
min-width: 0
&.count-notification--green
background-color: $green
35 changes: 35 additions & 0 deletions app/front/stylesheets/components/cards.sass
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,41 @@
display: block
.fr-text--lg
margin-bottom: 0
.comment__container
order: 3
margin-top: 1.25rem
background-color: var(--background-contrast-green-emeraude)
padding: 1rem 1.5rem
border-radius: 0.4em
position: relative
&::after
content: ''
position: absolute
bottom: 0
left: 80%
width: 0
height: 0
border: 26px solid transparent
border-top-color: var(--background-contrast-green-emeraude)
border-bottom: 0
border-right: 0
margin-left: -13px
margin-bottom: -26px
.comment__meta
font-size: 0.75rem
line-height: 1.5rem
margin-top: 0.5rem
text-align: right
.comment__title
position: relative
&::before
content: open-quote
margin-right: 0.5rem
&::after
content: close-quote
margin-left: 0.5rem
&::before, &::after
font-size: 2rem

// Carte reminders need =================================
.card-reminders-need
Expand Down
39 changes: 36 additions & 3 deletions app/models/company_satisfaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,31 @@
#
class CompanySatisfaction < ApplicationRecord
belongs_to :need, inverse_of: :company_satisfaction

has_one :diagnosis, through: :need, inverse_of: :company_satisfactions
has_one :solicitation, through: :diagnosis, inverse_of: :company_satisfactions
has_one :landing, through: :solicitation, inverse_of: :solicitations
has_one :landing_subject, through: :solicitation, inverse_of: :solicitations
has_one :subject, through: :need, inverse_of: :needs
has_one :theme, through: :need, inverse_of: :needs
has_one :theme, through: :need, source: :theme
has_many :matches, through: :need, inverse_of: :need
has_many :experts, through: :matches, source: :expert
has_many :facility_regions, through: :need, inverse_of: :needs
has_one :facility, through: :need, inverse_of: :needs

has_many :shared_satisfactions, inverse_of: :company_satisfaction
has_many :shared_satisfaction_users, through: :shared_satisfactions, source: :user
has_many :shared_satisfaction_experts, -> { distinct }, through: :shared_satisfactions, source: :expert

# Satisfaction pour les MER avec aide proposée
has_many :done_matches, -> { status_done }, class_name: 'Match', through: :need, inverse_of: :need, source: :matches
has_many :done_experts, class_name: 'Expert', through: :done_matches, source: :expert
has_many :done_users, class_name: 'User', through: :done_experts, source: :users
has_many :done_antennes, class_name: 'Antenne', through: :done_experts, source: :antenne
has_many :done_institutions, class_name: 'Institution', through: :done_antennes, source: :institution

validates :contacted_by_expert, :useful_exchange, inclusion: { in: [true, false] }
validates_associated :shared_satisfactions

scope :solicitation_mtm_campaign_cont, -> (query) {
joins(:solicitation).merge(Solicitation.mtm_campaign_cont(query))
Expand All @@ -54,8 +62,16 @@ class CompanySatisfaction < ApplicationRecord
joins(:solicitation).merge(Solicitation.mtm_campaign_end(query))
}

scope :shared, -> { joins(:shared_satisfactions) }
scope :not_shared, -> { where.missing(:shared_satisfactions) }

scope :shared_eq, -> (query) do
return self unless ['shared', 'not_shared'].include?(query)
self.send(query)
end

def self.ransackable_scopes(auth_object = nil)
%w[solicitation_mtm_campaign_cont solicitation_mtm_campaign_eq solicitation_mtm_campaign_start solicitation_mtm_campaign_end]
%w[solicitation_mtm_campaign_cont solicitation_mtm_campaign_eq solicitation_mtm_campaign_start solicitation_mtm_campaign_end shared_eq experts_id_eq]
end

def self.ransackable_attributes(auth_object = nil)
Expand All @@ -65,7 +81,24 @@ def self.ransackable_attributes(auth_object = nil)
def self.ransackable_associations(auth_object = nil)
[
"done_antennes", "done_experts", "done_institutions", "done_matches", "facility_regions", "landing",
"landing_subject", "matches", "need", "diagnosis", "solicitation", "subject", "theme", "facility"
"landing_subject", "matches", "need", "diagnosis", "solicitation", "subject", "theme", "facility", "experts"
]
end

# Partage aux conseillers
#
def share
done_experts.find_each do |e|
e.users.find_each{ |u| self.shared_satisfactions.create(user: u, expert: e) }
end
return true if self.valid?
self.shared_satisfactions.map{ |us| us.errors.full_messages.to_sentence }.uniq.each do |error|
self.errors.add(:base, error)
end
false
end

def shared
shared_satisfactions.any?
end
end
6 changes: 6 additions & 0 deletions app/models/expert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class Expert < ApplicationRecord
# :users
has_many :feedbacks, through: :users, source: :feedbacks, inverse_of: :experts

# :shared_satisfaction
has_many :shared_satisfactions, inverse_of: :expert
has_many :shared_company_satisfactions, -> { distinct }, through: :shared_satisfactions, source: :company_satisfaction

# Callbacks
after_update :synchronize_single_member, if: :personal_skillset?

Expand Down Expand Up @@ -225,6 +229,8 @@ class Expert < ApplicationRecord
scope :outputs, -> { joins(:reminders_registers).where(reminders_registers: RemindersRegister.current_output_category) }
scope :expired_needs, -> { joins(:reminders_registers).where(reminders_registers: RemindersRegister.current_expired_need_category) }

scope :without_shared_satisfaction, -> { where.missing(:shared_satisfactions) }

def self.apply_filters(params)
klass = self
klass = klass.omnisearch(params[:omnisearch]) if params[:omnisearch].present?
Expand Down
2 changes: 1 addition & 1 deletion app/models/institution_subject.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class InstitutionSubject < ApplicationRecord
# :experts_subjects
has_many :experts, through: :experts_subjects, inverse_of: :institutions_subjects
has_many :not_deleted_experts, through: :experts_subjects, inverse_of: :institutions_subjects
has_many :users, through: :experts, inverse_of: :experts_subjects
has_many :users, through: :experts, source: :users

# :institution
# Other InstitutionSubjects of the same Institution, and the same Subject.
Expand Down
4 changes: 0 additions & 4 deletions app/models/match_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
#
# index_match_filters_on_antenne_id (antenne_id)
#
# Foreign Keys
#
# fk_rails_... (antenne_id => antennes.id)
#
class MatchFilter < ApplicationRecord
## Associations
#
Expand Down
3 changes: 3 additions & 0 deletions app/models/need.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class Need < ApplicationRecord
# :subject
has_one :theme, through: :subject, inverse_of: :needs

# :company_satisfaction
has_many :shared_satisfactions, through: :company_satisfaction, source: :shared_satisfactions

## Scopes
#
NO_ACTIVITY_DELAY = 14.days
Expand Down
Loading

0 comments on commit 9bcbd82

Please sign in to comment.