diff --git a/app/assets/javascripts/new_design/champs/multiple_drop_down_list.js b/app/assets/javascripts/new_design/champs/multiple_drop_down_list.js index f76aa5913..27c3adb48 100644 --- a/app/assets/javascripts/new_design/champs/multiple_drop_down_list.js +++ b/app/assets/javascripts/new_design/champs/multiple_drop_down_list.js @@ -1,3 +1,9 @@ document.addEventListener('turbolinks:load', function() { $('select.select2').select2(); + + $('select.select2-limited').select2({ + 'placeholder': 'Sélectionnez des colonnes', + 'maximumSelectionLength': '2', + 'width': '300px' + }); }); diff --git a/app/assets/stylesheets/new_design/buttons.scss b/app/assets/stylesheets/new_design/buttons.scss index 6c9874b33..bff6394b4 100644 --- a/app/assets/stylesheets/new_design/buttons.scss +++ b/app/assets/stylesheets/new_design/buttons.scss @@ -172,6 +172,26 @@ } } +.dropdown-form { + padding: 2 * $default-spacer; + + .select2-container { + margin-bottom: 2 * $default-spacer; + } + + .select2-selection { + border: 1px solid $border-grey; + + &.select2-selection--multiple { + border: 1px solid $border-grey; + } + } +} + +.select2-dropdown { + border: 1px solid $border-grey; +} + .link { color: $blue; } diff --git a/app/controllers/new_gestionnaire/procedures_controller.rb b/app/controllers/new_gestionnaire/procedures_controller.rb index 6aa514c45..210b48d78 100644 --- a/app/controllers/new_gestionnaire/procedures_controller.rb +++ b/app/controllers/new_gestionnaire/procedures_controller.rb @@ -26,6 +26,9 @@ module NewGestionnaire def show @procedure = procedure + @displayed_fields = procedure_presentation.displayed_fields + @displayed_fields_values = displayed_fields_values + @a_suivre_dossiers = procedure .dossiers .includes(:user) @@ -64,9 +67,33 @@ module NewGestionnaire @archived_dossiers end + eager_load_displayed_fields + @dossiers = @dossiers.page([params[:page].to_i, 1].max) end + def update_displayed_fields + values = params[:values] + + if values.nil? + values = [] + end + + fields = values.map do |value| + table, column = value.split("/") + + c = procedure.fields.find do |field| + field['table'] == table && field['column'] == column + end + + c.to_json + end + + procedure_presentation.update_attributes(displayed_fields: fields) + + redirect_back(fallback_location: procedure_url(procedure)) + end + private def procedure @@ -85,5 +112,49 @@ module NewGestionnaire redirect_to avis_index_path end end + + def procedure_presentation + @procedure_presentation ||= current_gestionnaire.procedure_presentation_for_procedure_id(params[:procedure_id]) + end + + def displayed_fields_values + procedure_presentation.displayed_fields.map do |field| + "#{field['table']}/#{field['column']}" + end + end + + def eager_load_displayed_fields + @displayed_fields + .reject { |field| field['table'] == 'self' } + .group_by do |field| + if ['type_de_champ', 'type_de_champ_private'].include?(field['table']) + 'type_de_champ_group' + else + field['table'] + end + end.each do |_, fields| + + case fields.first['table'] + when'france_connect_information' + @dossiers = @dossiers.includes({ user: :france_connect_information }) + when 'type_de_champ', 'type_de_champ_private' + if fields.any? { |field| field['table'] == 'type_de_champ' } + @dossiers = @dossiers.includes(:champs) + end + + if fields.any? { |field| field['table'] == 'type_de_champ_private' } + @dossiers = @dossiers.includes(:champs_private) + end + + where_conditions = fields.map do |field| + "champs.type_de_champ_id = #{field['column']}" + end.join(" OR ") + + @dossiers = @dossiers.where(where_conditions) + else + @dossiers = @dossiers.includes(fields.first['table']) + end + end + end end end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 94cf0aa5c..4defbe794 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -330,6 +330,25 @@ class Dossier < ActiveRecord::Base end end + def get_value(table, column) + case table + when 'self' + self.send(column) + when 'user' + self.user.send(column) + when 'france_connect_information' + self.user.france_connect_information&.send(column) + when 'entreprise' + self.entreprise&.send(column) + when 'etablissement' + self.etablissement&.send(column) + when 'type_de_champ' + self.champs.find {|c| c.type_de_champ_id == column.to_i }.value + when 'type_de_champ_private' + self.champs_private.find {|c| c.type_de_champ_id == column.to_i }.value + end + end + private def build_attestation diff --git a/app/models/gestionnaire.rb b/app/models/gestionnaire.rb index 931ab09d2..7c4c060ac 100644 --- a/app/models/gestionnaire.rb +++ b/app/models/gestionnaire.rb @@ -123,6 +123,10 @@ class Gestionnaire < ActiveRecord::Base end end + def procedure_presentation_for_procedure_id(procedure_id) + assign_to.find_by(procedure_id: procedure_id).procedure_presentation_or_default + end + private def valid_couple_table_attr? table, column diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 1f0508c22..7c811d010 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -184,4 +184,61 @@ class Procedure < ActiveRecord::Base def without_continuation_mail_template without_continuation_mail || Mails::WithoutContinuationMail.default end + + def fields + fields = [ + field_hash('Créé le', 'self', 'created_at'), + field_hash('Mis à jour le', 'self', 'updated_at'), + field_hash('Demandeur', 'user', 'email') + ] + + fields << [ + field_hash('Civilité (FC)', 'france_connect_information', 'gender'), + field_hash('Prénom (FC)', 'france_connect_information', 'given_name'), + field_hash('Nom (FC)', 'france_connect_information', 'family_name') + ] + + if !for_individual || (for_individual && individual_with_siret) + fields << [ + field_hash('SIREN', 'entreprise', 'siren'), + field_hash('Forme juridique', 'entreprise', 'forme_juridique'), + field_hash('Nom commercial', 'entreprise', 'nom_commercial'), + field_hash('Raison sociale', 'entreprise', 'raison_sociale'), + field_hash('SIRET siège social', 'entreprise', 'siret_siege_social'), + field_hash('Date de création', 'entreprise', 'date_creation') + ] + + fields << [ + field_hash('SIRET', 'etablissement', 'siret'), + field_hash('Nom établissement', 'etablissement', 'libelle_naf'), + field_hash('Code postal', 'etablissement', 'code_postal') + ] + end + + types_de_champ.reject { |tdc| tdc.type_champ == 'header_section' }.each do |type_de_champ| + fields << field_hash(type_de_champ.libelle, 'type_de_champ', type_de_champ.id.to_s) + end + + types_de_champ_private.reject { |tdc| tdc.type_champ == 'header_section' }.each do |type_de_champ| + fields << field_hash(type_de_champ.libelle, 'type_de_champ_private', type_de_champ.id.to_s) + end + + fields.flatten + end + + def fields_for_select + fields.map do |field| + [field['label'], "#{field['table']}/#{field['column']}"] + end + end + + private + + def field_hash(label, table, column) + { + 'label' => label, + 'table' => table, + 'column' => column + } + end end diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index e2f45b492..f2779a16d 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -1,3 +1,9 @@ class ProcedurePresentation < ActiveRecord::Base belongs_to :assign_to + + def displayed_fields + read_attribute(:displayed_fields).map do |field| + field = JSON.parse(field) + end + end end diff --git a/app/views/new_gestionnaire/procedures/show.html.haml b/app/views/new_gestionnaire/procedures/show.html.haml index f2498d451..417bab614 100644 --- a/app/views/new_gestionnaire/procedures/show.html.haml +++ b/app/views/new_gestionnaire/procedures/show.html.haml @@ -56,9 +56,23 @@ %thead %tr %th.number-col Nº dossier - %th Demandeur + + - @displayed_fields.each do |field| + %th= field['label'] + %th.status-col Statut %th.follow-col + %span.button.dropdown + Personnaliser + .dropdown-content.fade-in-down + = form_tag update_displayed_fields_procedure_path(@procedure), method: :patch, class: 'dropdown-form' do + = select_tag :values, + options_for_select(@procedure.fields_for_select, + selected: @displayed_fields_values), + multiple: true, + class: 'select2-limited' + = submit_tag "Enregistrer", class: 'button' + %tbody - @dossiers.each do |dossier| %tr @@ -68,7 +82,12 @@ - if @followed_dossiers.with_unread_notifications.include?(dossier) %span.notifications{ 'aria-label': 'notifications' } = dossier.id - %td= link_to(dossier.user.email, dossier_path(@procedure, dossier), class: 'cell-link') + + - @displayed_fields.each do |field| + %td + = link_to(dossier_path(@procedure, dossier), class: 'cell-link') do + = dossier.get_value(field['table'], field['column']) + %td.status-col = link_to(dossier_path(@procedure, dossier), class: 'cell-link') do = render partial: 'status', locals: { dossier: dossier } diff --git a/config/routes.rb b/config/routes.rb index dbaa51e86..d09b9f6f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -237,6 +237,8 @@ Rails.application.routes.draw do scope module: 'new_gestionnaire' do resources :procedures, only: [:index, :show], param: :procedure_id do member do + patch 'update_displayed_fields' + resources :dossiers, only: [:show], param: :dossier_id do member do get 'attestation' diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index e258bd329..7b8172458 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -44,10 +44,16 @@ FactoryGirl.define do end trait :with_type_de_champ_private do - after(:build) do |procedure, _evaluator| - type_de_champ = create(:type_de_champ_private) + transient do + types_de_champ_private_count 1 + end - procedure.types_de_champ_private << type_de_champ + after(:build) do |procedure, evaluator| + evaluator.types_de_champ_private_count.times do + type_de_champ = create(:type_de_champ_private) + + procedure.types_de_champ_private << type_de_champ + end end end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 60418ad84..2b60d2c41 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -835,4 +835,28 @@ describe Dossier do it { expect(Dossier.count).to eq(0) } end end + + describe "#get_value" do + let(:dossier) { create(:dossier, :with_entreprise, user: user) } + + before do + FranceConnectInformation.create(france_connect_particulier_id: 123, user: user, gender: 'male') + + @champ_public = dossier.champs.first + @champ_public.value = "kiwi" + @champ_public.save + + @champ_private = dossier.champs_private.first + @champ_private.value = "banane" + @champ_private.save + end + + it { expect(dossier.get_value('self', 'created_at')).to eq(dossier.created_at) } + it { expect(dossier.get_value('user', 'email')).to eq(user.email) } + it { expect(dossier.get_value('france_connect_information', 'gender')).to eq(user.france_connect_information.gender) } + it { expect(dossier.get_value('entreprise', 'siren')).to eq(dossier.entreprise.siren) } + it { expect(dossier.get_value('etablissement', 'siret')).to eq(dossier.etablissement.siret) } + it { expect(dossier.get_value('type_de_champ', @champ_public.type_de_champ.id.to_s)).to eq(dossier.champs.first.value) } + it { expect(dossier.get_value('type_de_champ_private', @champ_private.type_de_champ.id.to_s)).to eq(dossier.champs_private.first.value) } + end end diff --git a/spec/models/gestionnaire_spec.rb b/spec/models/gestionnaire_spec.rb index 25d490fd1..8c5e16492 100644 --- a/spec/models/gestionnaire_spec.rb +++ b/spec/models/gestionnaire_spec.rb @@ -382,4 +382,12 @@ describe Gestionnaire, type: :model do it { is_expected.to eq({ }) } end end + + describe "procedure_presentation_for_procedure_id" do + let!(:procedure_assign_2) { create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2 } + let!(:pp) { ProcedurePresentation.create(assign_to: procedure_assign) } + + it { expect(gestionnaire.procedure_presentation_for_procedure_id(procedure.id)).to eq(pp)} + it { expect(gestionnaire.procedure_presentation_for_procedure_id(procedure_2.id).persisted?).to be_falsey} + end end diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb new file mode 100644 index 000000000..b59f1cecb --- /dev/null +++ b/spec/models/procedure_presentation_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe ProcedurePresentation do + let (:procedure_presentation_id) { ProcedurePresentation.create(displayed_fields: [ + { "label" => "test1", "table" => "user" }.to_json, + { "label" => "test2", "table" => "champs" }.to_json] + ).id } + let (:procedure_presentation) { ProcedurePresentation.find(procedure_presentation_id) } + + describe "#displayed_fields" do + it { expect(procedure_presentation.displayed_fields).to eq([{"label" => "test1", "table" => "user"}, {"label" => "test2", "table" => "champs"}]) } + end +end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 4a0244e23..a0323e567 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -421,4 +421,55 @@ describe Procedure do it { expect(Dossier.count).to eq(0) } end end + + describe "#fields" do + subject { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, :types_de_champ_count => 2, :types_de_champ_private_count => 2) } + let(:tdc_1) { subject.types_de_champ.first } + let(:tdc_2) { subject.types_de_champ.last } + let(:tdc_private_1) { subject.types_de_champ_private.first } + let(:tdc_private_2) { subject.types_de_champ_private.last } + let(:expected) { + [ + { "label" => 'Créé le', "table" => 'self', "column" => 'created_at' }, + { "label" => 'Mis à jour le', "table" => 'self', "column" => 'updated_at' }, + { "label" => 'Demandeur', "table" => 'user', "column" => 'email' }, + { "label" => 'Civilité (FC)', "table" => 'france_connect_information', "column" => 'gender' }, + { "label" => 'Prénom (FC)', "table" => 'france_connect_information', "column" => 'given_name' }, + { "label" => 'Nom (FC)', "table" => 'france_connect_information', "column" => 'family_name' }, + { "label" => 'SIREN', "table" => 'entreprise', "column" => 'siren' }, + { "label" => 'Forme juridique', "table" => 'entreprise', "column" => 'forme_juridique' }, + { "label" => 'Nom commercial', "table" => 'entreprise', "column" => 'nom_commercial' }, + { "label" => 'Raison sociale', "table" => 'entreprise', "column" => 'raison_sociale' }, + { "label" => 'SIRET siège social', "table" => 'entreprise', "column" => 'siret_siege_social' }, + { "label" => 'Date de création', "table" => 'entreprise', "column" => 'date_creation' }, + { "label" => 'SIRET', "table" => 'etablissement', "column" => 'siret' }, + { "label" => 'Nom établissement', "table" => 'etablissement', "column" => 'libelle_naf' }, + { "label" => 'Code postal', "table" => 'etablissement', "column" => 'code_postal' }, + { "label" => tdc_1.libelle, "table" => 'type_de_champ', "column" => tdc_1.id.to_s }, + { "label" => tdc_2.libelle, "table" => 'type_de_champ', "column" => tdc_2.id.to_s }, + { "label" => tdc_private_1.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_1.id.to_s }, + { "label" => tdc_private_2.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_2.id.to_s } + ] + } + + it { expect(subject.fields).to eq(expected) } + end + + describe "#fields_for_select" do + subject { create(:procedure) } + + before do + allow(subject).to receive(:fields).and_return([{ + "label" => "label1", + "table" => "table1", + "column" => "column1" + }, { + "label" => "label2", + "table" => "table2", + "column" => "column2" + }]) + end + + it { expect(subject.fields_for_select).to eq([["label1", "table1/column1"], ["label2", "table2/column2"]]) } + end end