From d26ae9539d78b4cd9547247bc5b38f29267e05c3 Mon Sep 17 00:00:00 2001 From: Xavier J Date: Mon, 18 Jul 2016 18:24:29 +0200 Subject: [PATCH] An accompagnateur can be mark a dossier follow by us --- .../backoffice/dossiers_controller.rb | 7 + app/controllers/commentaires_controller.rb | 4 + app/models/dossier.rb | 1 + app/models/follow.rb | 6 + app/models/gestionnaire.rb | 22 +++ app/views/admin/procedures/_list.html.haml | 2 +- app/views/backoffice/dossiers/_list.html.haml | 22 ++- app/views/backoffice/dossiers/show.html.haml | 5 + config/routes.rb | 2 + ...8124741_gestionnaire_can_follow_dossier.rb | 8 ++ db/schema.rb | 10 +- .../commentaires_controller_spec.rb | 25 +++- .../backoffice/dossiers_controller_spec.rb | 43 +++++- spec/factories/follow.rb | 4 + spec/models/dossier_spec.rb | 1 + spec/models/gestionnaire_spec.rb | 126 +++++++++++++++--- .../dossiers/index_html.haml_spec.rb | 4 + 17 files changed, 256 insertions(+), 36 deletions(-) create mode 100644 app/models/follow.rb create mode 100644 db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb create mode 100644 spec/factories/follow.rb diff --git a/app/controllers/backoffice/dossiers_controller.rb b/app/controllers/backoffice/dossiers_controller.rb index 6f3e8b453..e50024c36 100644 --- a/app/controllers/backoffice/dossiers_controller.rb +++ b/app/controllers/backoffice/dossiers_controller.rb @@ -54,6 +54,13 @@ class Backoffice::DossiersController < ApplicationController render 'show' end + def follow + follow = current_gestionnaire.toggle_follow_dossier params[:dossier_id] + + flash.notice = (follow.class == Follow ? 'Dossier suivi' : 'Dossier relaché') + redirect_to request.referer + end + private def dossiers_to_display diff --git a/app/controllers/commentaires_controller.rb b/app/controllers/commentaires_controller.rb index 4a0b75662..bea003766 100644 --- a/app/controllers/commentaires_controller.rb +++ b/app/controllers/commentaires_controller.rb @@ -26,6 +26,10 @@ class CommentairesController < ApplicationController saved = @commentaire.save unless flash.alert if is_gestionnaire? + unless current_gestionnaire.follow? @commentaire.dossier + current_gestionnaire.toggle_follow_dossier @commentaire.dossier + end + NotificationMailer.new_answer(@commentaire.dossier).deliver_now! if saved redirect_to url_for(controller: 'backoffice/dossiers', action: :show, id: params['dossier_id']) elsif current_user.email != @commentaire.dossier.user.email diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 80e212454..28a0c5074 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -18,6 +18,7 @@ class Dossier < ActiveRecord::Base has_many :cadastres, dependent: :destroy has_many :commentaires, dependent: :destroy has_many :invites, dependent: :destroy + has_many :follows belongs_to :procedure belongs_to :user diff --git a/app/models/follow.rb b/app/models/follow.rb new file mode 100644 index 000000000..d554d8fe6 --- /dev/null +++ b/app/models/follow.rb @@ -0,0 +1,6 @@ +class Follow < ActiveRecord::Base + belongs_to :gestionnaire + belongs_to :dossier + + validates_uniqueness_of :gestionnaire_id, :scope => :dossier_id +end \ No newline at end of file diff --git a/app/models/gestionnaire.rb b/app/models/gestionnaire.rb index e01fe47a2..128783937 100644 --- a/app/models/gestionnaire.rb +++ b/app/models/gestionnaire.rb @@ -7,12 +7,34 @@ class Gestionnaire < ActiveRecord::Base has_many :assign_to, dependent: :destroy has_many :procedures, through: :assign_to has_many :dossiers, through: :procedures + has_many :follows def dossiers_filter dossiers.where(procedure_id: procedure_filter_list) end + def dossiers_follow + dossiers.joins(:follows).where("follows.gestionnaire_id = #{id}") + end + def procedure_filter_list procedure_filter.empty? ? procedures.pluck(:id) : procedure_filter end + + def toggle_follow_dossier dossier_id + dossier = dossier_id + dossier = Dossier.find(dossier_id) unless dossier_id.class == Dossier + + Follow.create!(dossier: dossier, gestionnaire: self) + rescue ActiveRecord::RecordInvalid + Follow.where(dossier: dossier, gestionnaire: self).delete_all + rescue ActiveRecord::RecordNotFound + nil + end + + def follow? dossier_id + dossier_id = dossier_id.id if dossier_id.class == Dossier + + Follow.where(gestionnaire_id: id, dossier_id: dossier_id).any? + end end diff --git a/app/views/admin/procedures/_list.html.haml b/app/views/admin/procedures/_list.html.haml index fb399add6..459585388 100644 --- a/app/views/admin/procedures/_list.html.haml +++ b/app/views/admin/procedures/_list.html.haml @@ -11,7 +11,7 @@ - @procedures.each do |procedure| - procedure = procedure.decorate %tr - %td.col-md-1.col-lg-1= procedure.id + %td= procedure.id %td.col-md-6.col-lg-6 = link_to(procedure.libelle, "/admin/procedures/#{procedure.id}") - if @active_class diff --git a/app/views/backoffice/dossiers/_list.html.haml b/app/views/backoffice/dossiers/_list.html.haml index 176b093f7..116d10802 100644 --- a/app/views/backoffice/dossiers/_list.html.haml +++ b/app/views/backoffice/dossiers/_list.html.haml @@ -1,19 +1,27 @@ - unless smart_listing.empty? %table.table - %thead.row - %th.col-md-4.col-lg-4= smart_listing.sortable 'Procédure', 'procedure.libelle' - %th.col-md-4.col-lg-4= smart_listing.sortable 'Dossier', 'nom_projet' - %th.col-md-2.col-lg-2= smart_listing.sortable 'État', 'state' - %th.col-md-2.col-lg-2= smart_listing.sortable 'Date de mise à jour', 'updated_at' + %thead + %th= smart_listing.sortable 'Procédure', 'procedure.libelle' + %th= smart_listing.sortable 'Dossier', 'nom_projet' + %th= smart_listing.sortable 'État', 'state' + %th= smart_listing.sortable 'Date de mise à jour', 'updated_at' + - unless @liste == 'termine' + %th Actions - @dossiers.each do |dossier| - dossier = dossier.decorate %tr - %td= dossier.procedure.libelle - %td + %td.col-md-4.col-lg-4= dossier.procedure.libelle + %td.col-md-4.col-lg-4 = link_to(dossier.nom_projet, "/backoffice/dossiers/#{dossier.id}") %td= dossier.display_state %td= dossier.last_update + - unless @liste == 'termine' + %td + - if current_gestionnaire.follow?(dossier.id) + = link_to('Quitter'.html_safe, backoffice_dossier_follow_path(dossier_id: dossier.id), 'data-method' => :put, class: 'btn-sm btn-danger', id: "suivre_dossier_#{dossier.id}") + -else + = link_to('Suivre', backoffice_dossier_follow_path(dossier_id: dossier.id), 'data-method' => :put, class: 'btn-sm btn-primary', id: "suivre_dossier_#{dossier.id}") = smart_listing.paginate = smart_listing.pagination_per_page_links diff --git a/app/views/backoffice/dossiers/show.html.haml b/app/views/backoffice/dossiers/show.html.haml index e24c2b978..de4f02061 100644 --- a/app/views/backoffice/dossiers/show.html.haml +++ b/app/views/backoffice/dossiers/show.html.haml @@ -6,6 +6,11 @@ %h3{:class => 'text-success'} = @facade.dossier.display_state + - if current_gestionnaire.follow?(@facade.dossier.id) + = link_to('Quitter'.html_safe, backoffice_dossier_follow_path(dossier_id: @facade.dossier.id), 'data-method' => :put, class: 'btn btn-md btn-danger', id: "suivre_dossier_#{@facade.dossier.id}") + -else + = link_to('Suivre', backoffice_dossier_follow_path(dossier_id: @facade.dossier.id), 'data-method' => :put, class: 'btn btn-md btn-primary', id: "suivre_dossier_#{@facade.dossier.id}") + = render partial: '/dossiers/infos_entreprise' = render partial: '/dossiers/infos_dossier' diff --git a/config/routes.rb b/config/routes.rb index 7012e3e72..c4fc2e608 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -143,6 +143,8 @@ Rails.application.routes.draw do post 'close' => 'dossiers#close' post 'invites' => '/invites#create' + + put 'follow' => 'dossiers#follow' end resources :commentaires, only: [:create] diff --git a/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb b/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb new file mode 100644 index 000000000..15247e65f --- /dev/null +++ b/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb @@ -0,0 +1,8 @@ +class GestionnaireCanFollowDossier < ActiveRecord::Migration + def change + create_table :follows do |t| + t.belongs_to :gestionnaire, index: true + t.belongs_to :dossier, index: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 99627734d..1dacf946f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160622081322) do +ActiveRecord::Schema.define(version: 20160718124741) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -168,6 +168,14 @@ ActiveRecord::Schema.define(version: 20160622081322) do t.integer "etablissement_id" end + create_table "follows", force: :cascade do |t| + t.integer "gestionnaire_id" + t.integer "dossier_id" + end + + add_index "follows", ["dossier_id"], name: "index_follows_on_dossier_id", using: :btree + add_index "follows", ["gestionnaire_id"], name: "index_follows_on_gestionnaire_id", using: :btree + create_table "france_connect_informations", force: :cascade do |t| t.string "gender" t.string "given_name" diff --git a/spec/controllers/backoffice/commentaires_controller_spec.rb b/spec/controllers/backoffice/commentaires_controller_spec.rb index a85f0cc99..18e51695d 100644 --- a/spec/controllers/backoffice/commentaires_controller_spec.rb +++ b/spec/controllers/backoffice/commentaires_controller_spec.rb @@ -5,6 +5,7 @@ describe Backoffice::CommentairesController, type: :controller do let(:dossier_id) { dossier.id } let(:email_commentaire) { 'test@test.com' } let(:texte_commentaire) { 'Commentaire de test' } + let(:gestionnaire) { create(:gestionnaire) } before do allow(ClamavService).to receive(:safe_file?).and_return(true) @@ -12,16 +13,32 @@ describe Backoffice::CommentairesController, type: :controller do describe '#POST create' do before do - sign_in create(:gestionnaire) + sign_in gestionnaire end + context "création correct d'un commentaire" do + subject { post :create, dossier_id: dossier_id, email_commentaire: email_commentaire, texte_commentaire: texte_commentaire } + it 'depuis la page admin' do - post :create, dossier_id: dossier_id, email_commentaire: email_commentaire, texte_commentaire: texte_commentaire expect(response).to redirect_to("/backoffice/dossiers/#{dossier_id}") end + + it 'gestionnaire is automatically affect to follow the dossier' do + expect { subject }.to change(Follow, :count).by(1) + end + + context 'when gestionnaire already follow dossier' do + before do + create :follow, gestionnaire_id: gestionnaire.id, dossier_id: dossier_id + end + + it 'gestionnaire is automatically affect to follow the dossier' do + expect { subject }.to change(Follow, :count).by(0) + end + end end - context 'when document is upload whith a commentaire', vcr: { cassette_name: 'controllers_backoffice_commentaires_controller_doc_upload_with_comment' } do + context 'when document is upload whith a commentaire', vcr: {cassette_name: 'controllers_backoffice_commentaires_controller_doc_upload_with_comment'} do let(:document_upload) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') } subject do @@ -80,7 +97,7 @@ describe Backoffice::CommentairesController, type: :controller do subject { dossier.state } - it {is_expected.to eq('replied')} + it { is_expected.to eq('replied') } it 'Notification email is send' do expect(NotificationMailer).to receive(:new_answer).and_return(NotificationMailer) diff --git a/spec/controllers/backoffice/dossiers_controller_spec.rb b/spec/controllers/backoffice/dossiers_controller_spec.rb index 895c0e4a5..8b23017b3 100644 --- a/spec/controllers/backoffice/dossiers_controller_spec.rb +++ b/spec/controllers/backoffice/dossiers_controller_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe Backoffice::DossiersController, type: :controller do let(:dossier) { create(:dossier, :with_entreprise) } - let(:dossier_archived) { create(:dossier, :with_entreprise, archived: true) } + let(:dossier_archived) { create(:dossier, :with_entreprise, archived: true) } let(:dossier_id) { dossier.id } let(:bad_dossier_id) { Dossier.count + 10 } @@ -67,6 +67,19 @@ describe Backoffice::DossiersController, type: :controller do end end + describe 'GET #suivi' do + context 'when gestionnaire is connected' do + before do + sign_in gestionnaire + end + + it 'returns http success' do + get :index, liste: :suivi + expect(response).to have_http_status(200) + end + end + end + describe 'GET #termine' do context 'when gestionnaire is connected' do before do @@ -128,4 +141,32 @@ describe Backoffice::DossiersController, type: :controller do expect(dossier.state).to eq('closed') end end + + describe 'PUT #toggle_follow' do + before do + sign_in gestionnaire + end + + subject { put :follow, dossier_id: dossier_id } + + it { expect(subject.status).to eq 302 } + it { is_expected.to redirect_to backoffice_dossiers_path } + + describe 'flash alert' do + context 'when dossier is not follow by gestionnaire' do + before do + subject + end + it { expect(flash[:notice]).to have_content 'Dossier suivi' } + end + + context 'when dossier is follow by gestionnaire' do + before do + create :follow, gestionnaire_id: gestionnaire.id, dossier_id: dossier.id + subject + end + it { expect(flash[:notice]).to have_content 'Dossier relaché' } + end + end + end end diff --git a/spec/factories/follow.rb b/spec/factories/follow.rb new file mode 100644 index 000000000..9db1f67ce --- /dev/null +++ b/spec/factories/follow.rb @@ -0,0 +1,4 @@ +FactoryGirl.define do + factory :follow do + end +end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index c9ae004e5..3f20d3fb4 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -24,6 +24,7 @@ describe Dossier do it { is_expected.to have_one(:entreprise) } it { is_expected.to belong_to(:user) } it { is_expected.to have_many(:invites) } + it { is_expected.to have_many(:follows) } end describe 'delegation' do diff --git a/spec/models/gestionnaire_spec.rb b/spec/models/gestionnaire_spec.rb index a7aea4737..17a8b55a2 100644 --- a/spec/models/gestionnaire_spec.rb +++ b/spec/models/gestionnaire_spec.rb @@ -1,6 +1,17 @@ require 'rails_helper' describe Gestionnaire, type: :model do + let(:admin) { create :administrateur } + let!(:procedure) { create :procedure, administrateur: admin } + let!(:procedure_2) { create :procedure, administrateur: admin } + let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] } + let(:procedure_filter) { [] } + + before do + create :assign_to, gestionnaire: gestionnaire, procedure: procedure + create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2 + end + describe 'database column' do it { is_expected.to have_db_column(:email) } it { is_expected.to have_db_column(:encrypted_password) } @@ -20,20 +31,11 @@ describe Gestionnaire, type: :model do it { is_expected.to have_and_belong_to_many(:administrateurs) } it { is_expected.to have_many(:procedures) } it { is_expected.to have_many(:dossiers) } + it { is_expected.to have_many(:follows) } end describe '#dossiers_filter' do - let(:admin) { create :administrateur } - let(:procedure) { create :procedure, administrateur: admin } - let(:procedure_2) { create :procedure, administrateur: admin } - let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] } let!(:dossier) { create :dossier, procedure: procedure } - let(:procedure_filter) { [] } - - before do - create :assign_to, gestionnaire: gestionnaire, procedure: procedure - create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2 - end subject { gestionnaire.dossiers_filter } @@ -49,18 +51,6 @@ describe Gestionnaire, type: :model do end describe '#procedure_filter_list' do - let(:admin) { create :administrateur } - let!(:procedure) { create :procedure, administrateur: admin } - let!(:procedure_2) { create :procedure, administrateur: admin } - let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] } - - before do - create :assign_to, gestionnaire: gestionnaire, procedure: procedure - create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2 - end - - let(:procedure_filter) { [] } - subject { gestionnaire.procedure_filter_list } context 'when gestionnaire procedure_filter is empty' do @@ -73,4 +63,96 @@ describe Gestionnaire, type: :model do it { expect(subject).to eq [procedure.id] } end end + + describe '#toggle_follow_dossier' do + let!(:dossier) { create :dossier, procedure: procedure } + + subject { gestionnaire.toggle_follow_dossier dossier_id } + + context 'when dossier id not valid' do + let(:dossier_id) { 0 } + + it { expect(subject).to eq nil } + end + + context 'when dossier id is valid' do + let(:dossier_id) { dossier.id } + + context 'when dossier is not follow by gestionnaire' do + it 'value change in database' do + expect { subject }.to change(Follow, :count).by(1) + end + + it { expect(subject).to be_an_instance_of Follow } + end + + context 'when dossier is follow by gestionnaire' do + before do + create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id + end + + it 'value change in database' do + expect { subject }.to change(Follow, :count).by(-1) + end + + it { expect(subject).to eq 1 } + end + end + + context 'when dossier instance is past' do + let(:dossier_id) { dossier } + + context 'when dossier is not follow by gestionnaire' do + it 'value change in database' do + expect { subject }.to change(Follow, :count).by(1) + end + + it { expect(subject).to be_an_instance_of Follow } + end + + context 'when dossier is follow by gestionnaire' do + before do + create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id + end + + it 'value change in database' do + expect { subject }.to change(Follow, :count).by(-1) + end + + it { expect(subject).to eq 1 } + end + end + end + + describe '#follow?' do + let!(:dossier) { create :dossier, procedure: procedure } + + subject { gestionnaire.follow? dossier.id } + + context 'when gestionnaire follow a dossier' do + + before do + create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id + end + + it { is_expected.to be_truthy } + end + + context 'when gestionnaire not follow a dossier' do + it { is_expected.to be_falsey } + end + end + + describe '#dossiers_follow' do + let!(:dossier) { create :dossier, procedure: procedure } + + before do + create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id + end + + subject { gestionnaire.dossiers_follow } + + it { expect(Follow.all.size).to eq 1 } + it { expect(subject.first).to eq dossier } + end end diff --git a/spec/views/backoffice/dossiers/index_html.haml_spec.rb b/spec/views/backoffice/dossiers/index_html.haml_spec.rb index 5cc52453a..9127a12df 100644 --- a/spec/views/backoffice/dossiers/index_html.haml_spec.rb +++ b/spec/views/backoffice/dossiers/index_html.haml_spec.rb @@ -36,6 +36,8 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do it { is_expected.not_to have_content(decorate_dossier_replied.nom_projet) } it { is_expected.not_to have_content(decorate_dossier_closed.nom_projet) } + it { is_expected.to have_css("#suivre_dossier_#{gestionnaire.dossiers.waiting_for_gestionnaire.first.id}") } + describe 'active tab' do it { is_expected.to have_selector('.active .text-danger') } end @@ -90,6 +92,8 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do it { is_expected.not_to have_content(decorate_dossier_initiated.nom_projet) } it { is_expected.not_to have_content(decorate_dossier_replied.nom_projet) } + it { is_expected.not_to have_css("#suivre_dossier_#{gestionnaire.dossiers.termine.first.id}") } + describe 'active tab' do it { is_expected.to have_selector('.active .text-success') } end