From 29e9f2dd32f5cb659726ada3d860135948ea495b Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Jan 2021 15:45:02 +0100 Subject: [PATCH 01/17] Ajout du model expert Co-authored-by: Kara Diaby --- app/models/expert.rb | 11 +++++++++++ app/models/user.rb | 2 ++ db/migrate/20210107143316_create_experts.rb | 7 +++++++ db/migrate/20210107143938_link_user_and_expert.rb | 6 ++++++ db/schema.rb | 10 +++++++++- 5 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 app/models/expert.rb create mode 100644 db/migrate/20210107143316_create_experts.rb create mode 100644 db/migrate/20210107143938_link_user_and_expert.rb diff --git a/app/models/expert.rb b/app/models/expert.rb new file mode 100644 index 000000000..9564353cb --- /dev/null +++ b/app/models/expert.rb @@ -0,0 +1,11 @@ +# == Schema Information +# +# Table name: experts +# +# id :bigint not null, primary key +# created_at :datetime not null +# updated_at :datetime not null +# +class Expert < ApplicationRecord + has_one :user +end diff --git a/app/models/user.rb b/app/models/user.rb index d1356face..4778ed6b7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,6 +25,7 @@ # created_at :datetime # updated_at :datetime # administrateur_id :bigint +# expert_id :bigint # instructeur_id :bigint # class User < ApplicationRecord @@ -48,6 +49,7 @@ class User < ApplicationRecord has_one :france_connect_information, dependent: :destroy belongs_to :instructeur, optional: true belongs_to :administrateur, optional: true + belongs_to :expert, optional: true accepts_nested_attributes_for :france_connect_information diff --git a/db/migrate/20210107143316_create_experts.rb b/db/migrate/20210107143316_create_experts.rb new file mode 100644 index 000000000..b31a81a99 --- /dev/null +++ b/db/migrate/20210107143316_create_experts.rb @@ -0,0 +1,7 @@ +class CreateExperts < ActiveRecord::Migration[6.0] + def change + create_table :experts do |t| # rubocop:disable Style/SymbolProc + t.timestamps + end + end +end diff --git a/db/migrate/20210107143938_link_user_and_expert.rb b/db/migrate/20210107143938_link_user_and_expert.rb new file mode 100644 index 000000000..83c59c08a --- /dev/null +++ b/db/migrate/20210107143938_link_user_and_expert.rb @@ -0,0 +1,6 @@ +class LinkUserAndExpert < ActiveRecord::Migration[6.0] + def change + add_reference :users, :expert, index: true + add_foreign_key :users, :experts + end +end diff --git a/db/schema.rb b/db/schema.rb index d32d42068..fb335bd56 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_01_14_224721) do +ActiveRecord::Schema.define(version: 2021_01_07_143938) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -321,6 +321,11 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) do t.datetime "updated_at" end + create_table "experts", force: :cascade do |t| + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "exports", force: :cascade do |t| t.string "format", null: false t.datetime "created_at", null: false @@ -676,9 +681,11 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) do t.datetime "locked_at" t.bigint "instructeur_id" t.bigint "administrateur_id" + t.bigint "expert_id" t.index ["administrateur_id"], name: "index_users_on_administrateur_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true + t.index ["expert_id"], name: "index_users_on_expert_id" t.index ["instructeur_id"], name: "index_users_on_instructeur_id" t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true @@ -734,6 +741,7 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) do add_foreign_key "types_de_champ", "procedure_revisions", column: "revision_id" add_foreign_key "types_de_champ", "types_de_champ", column: "parent_id" add_foreign_key "users", "administrateurs" + add_foreign_key "users", "experts" add_foreign_key "users", "instructeurs" add_foreign_key "without_continuation_mails", "procedures" end From d409a9a6c510897c562319bff51a7b7950ef7556 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Jan 2021 15:45:02 +0100 Subject: [PATCH 02/17] Procedure and expert link --- app/models/experts_procedure.rb | 16 ++++++++++++++++ app/models/procedure.rb | 3 +++ .../20210112120658_create_experts_procedures.rb | 11 +++++++++++ db/schema.rb | 14 +++++++++++++- spec/models/expert_spec.rb | 16 ++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/models/experts_procedure.rb create mode 100644 db/migrate/20210112120658_create_experts_procedures.rb create mode 100644 spec/models/expert_spec.rb diff --git a/app/models/experts_procedure.rb b/app/models/experts_procedure.rb new file mode 100644 index 000000000..b8fa90b99 --- /dev/null +++ b/app/models/experts_procedure.rb @@ -0,0 +1,16 @@ +# == Schema Information +# +# Table name: experts_procedures +# +# id :bigint not null, primary key +# allow_decision_access :boolean default(FALSE), not null +# created_at :datetime not null +# updated_at :datetime not null +# expert_id :bigint not null +# procedure_id :bigint not null +# +class ExpertsProcedure < ApplicationRecord + belongs_to :expert + belongs_to :procedure + validates :expert, uniqueness: { scope: :procedure } +end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 4055bb7c9..eed64273b 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -70,6 +70,9 @@ class Procedure < ApplicationRecord has_many :all_types_de_champ, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id').ordered }, through: :revisions, source: :types_de_champ has_many :all_types_de_champ_private, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id').ordered }, through: :revisions, source: :types_de_champ_private + has_many :experts_procedures, dependent: :destroy + has_many :experts, through: :experts_procedures + has_one :module_api_carto, dependent: :destroy has_one :attestation_template, dependent: :destroy diff --git a/db/migrate/20210112120658_create_experts_procedures.rb b/db/migrate/20210112120658_create_experts_procedures.rb new file mode 100644 index 000000000..122fc1c55 --- /dev/null +++ b/db/migrate/20210112120658_create_experts_procedures.rb @@ -0,0 +1,11 @@ +class CreateExpertsProcedures < ActiveRecord::Migration[6.0] + def change + create_table :experts_procedures do |t| + t.references :expert, null: false, foreign_key: true + t.references :procedure, null: false, foreign_key: true + t.boolean :allow_decision_access, default: false, null: false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index fb335bd56..26d4e415f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_01_07_143938) do +ActiveRecord::Schema.define(version: 2021_01_13_150013) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -326,6 +326,16 @@ ActiveRecord::Schema.define(version: 2021_01_07_143938) do t.datetime "updated_at", precision: 6, null: false end + create_table "experts_procedures", force: :cascade do |t| + t.bigint "expert_id", null: false + t.bigint "procedure_id", null: false + t.boolean "allow_decision_access", default: false, null: false + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["expert_id"], name: "index_experts_procedures_on_expert_id" + t.index ["procedure_id"], name: "index_experts_procedures_on_procedure_id" + end + create_table "exports", force: :cascade do |t| t.string "format", null: false t.datetime "created_at", null: false @@ -722,6 +732,8 @@ ActiveRecord::Schema.define(version: 2021_01_07_143938) do add_foreign_key "dossiers", "groupe_instructeurs" add_foreign_key "dossiers", "procedure_revisions", column: "revision_id" add_foreign_key "dossiers", "users" + add_foreign_key "experts_procedures", "experts" + add_foreign_key "experts_procedures", "procedures" add_foreign_key "feedbacks", "users" add_foreign_key "geo_areas", "champs" add_foreign_key "groupe_instructeurs", "procedures" diff --git a/spec/models/expert_spec.rb b/spec/models/expert_spec.rb new file mode 100644 index 000000000..ec85e62f6 --- /dev/null +++ b/spec/models/expert_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +RSpec.describe Expert, type: :model do + describe 'an expert could be add to a procedure' do + + let(:procedure) { create(:procedure) } + let(:expert) { Expert.create } + + before do + procedure.experts << expert + procedure.reload + end + + it { expect(procedure.experts).to eq([expert]) } + end +end From e0cb0eebab88eb780d4b69cc77dc9cfcc84b8aef Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Tue, 12 Jan 2021 15:08:57 +0100 Subject: [PATCH 03/17] Tests : add an expert to a procedure and put give him the access to see the dossier final decision --- spec/models/expert_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/models/expert_spec.rb b/spec/models/expert_spec.rb index ec85e62f6..65d15c7d2 100644 --- a/spec/models/expert_spec.rb +++ b/spec/models/expert_spec.rb @@ -1,8 +1,5 @@ -require 'rails_helper' - RSpec.describe Expert, type: :model do describe 'an expert could be add to a procedure' do - let(:procedure) { create(:procedure) } let(:expert) { Expert.create } @@ -12,5 +9,7 @@ RSpec.describe Expert, type: :model do end it { expect(procedure.experts).to eq([expert]) } + it { expect(ExpertsProcedure.where(expert: expert, procedure: procedure).count).to eq(1) } + it { expect(ExpertsProcedure.where(expert: expert, procedure: procedure).first.allow_decision_access).to be_falsy } end end From da067597ab628adf35fa84578a4aea9f1143f210 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Fri, 15 Jan 2021 16:33:36 +0100 Subject: [PATCH 04/17] Add create expert method --- app/models/user.rb | 14 +++++++++++ spec/models/user_spec.rb | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 4778ed6b7..d2a449528 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -130,6 +130,20 @@ class User < ApplicationRecord user end + def self.create_or_promote_to_expert(email, password) + user = User + .create_with(password: password, confirmed_at: Time.zone.now) + .find_or_create_by(email: email) + + if user.valid? + if user.expert_id.nil? + user.create_expert! + end + end + + user + end + def flipper_id "User:#{id}" end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c480cec27..459fbae5d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -163,6 +163,57 @@ describe User, type: :model do end end + describe '.create_or_promote_to_expert' do + let(:email) { 'exp1@gmail.com' } + let(:password) { 'un super expert !' } + + subject { User.create_or_promote_to_expert(email, password) } + + context 'with an invalid email' do + let(:email) { 'invalid' } + + it 'does not build an expert' do + user = subject + expect(user.valid?).to be false + expect(user.expert).to be_nil + end + end + + context 'without an existing user' do + it do + user = subject + expect(user.valid_password?(password)).to be true + expect(user.confirmed_at).to be_present + expect(user.expert).to be_present + end + end + + context 'with an existing user' do + before { create(:user, email: email, password: 'my-s3cure-p4ssword') } + + it 'keeps the previous password' do + user = subject + expect(user.valid_password?('my-s3cure-p4ssword')).to be true + expect(user.expert).to be_present + end + + context 'with an existing expert' do + let!(:expert) { Expert.create } + + before do + User + .find_by(email: email) + .update!(expert: expert) + end + + it 'keeps the existing experts' do + user = subject + expect(user.expert).to eq(expert) + end + end + end + end + describe 'invite_administrateur!' do let(:super_admin) { create(:super_admin) } let(:administrateur) { create(:administrateur) } From efbff0f2e090f0199817310fba969ab0bf1fb46d Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Fri, 15 Jan 2021 16:33:36 +0100 Subject: [PATCH 05/17] add expert factory --- spec/factories/expert.rb | 14 ++++++++++++++ spec/models/expert_spec.rb | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 spec/factories/expert.rb diff --git a/spec/factories/expert.rb b/spec/factories/expert.rb new file mode 100644 index 000000000..7e1b5863e --- /dev/null +++ b/spec/factories/expert.rb @@ -0,0 +1,14 @@ +FactoryBot.define do + sequence(:create_expert_email) { |n| "expert#{n}@expert.com" } + + factory :expert do + transient do + email { generate(:expert_email) } + password { 'somethingverycomplated!' } + end + + initialize_with do + User.create_or_promote_to_expert(email, password).expert + end + end +end diff --git a/spec/models/expert_spec.rb b/spec/models/expert_spec.rb index 65d15c7d2..2b3dd1c78 100644 --- a/spec/models/expert_spec.rb +++ b/spec/models/expert_spec.rb @@ -1,7 +1,7 @@ RSpec.describe Expert, type: :model do describe 'an expert could be add to a procedure' do let(:procedure) { create(:procedure) } - let(:expert) { Expert.create } + let(:expert) { create(:expert) } before do procedure.experts << expert From b683c2023ba0fdab0d31a4db102bffbc19b14896 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Fri, 15 Jan 2021 16:39:07 +0100 Subject: [PATCH 06/17] add expert to avis table --- app/models/avis.rb | 25 +++++++++++-------- app/models/experts_procedure.rb | 3 ++- ...113084256_add_experts_procedure_to_avis.rb | 5 ++++ db/schema.rb | 5 +++- 4 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 db/migrate/20210113084256_add_experts_procedure_to_avis.rb diff --git a/app/models/avis.rb b/app/models/avis.rb index 62d89b8ad..a0d74704b 100644 --- a/app/models/avis.rb +++ b/app/models/avis.rb @@ -2,27 +2,30 @@ # # Table name: avis # -# id :integer not null, primary key -# answer :text -# confidentiel :boolean default(FALSE), not null -# email :string -# introduction :text -# revoked_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# claimant_id :integer not null -# dossier_id :integer -# instructeur_id :integer +# id :integer not null, primary key +# answer :text +# confidentiel :boolean default(FALSE), not null +# email :string +# introduction :text +# revoked_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# claimant_id :integer not null +# dossier_id :integer +# experts_procedure_id :bigint +# instructeur_id :integer # class Avis < ApplicationRecord include EmailSanitizableConcern belongs_to :dossier, inverse_of: :avis, touch: true, optional: false belongs_to :instructeur, optional: true + belongs_to :experts_procedure, optional: true belongs_to :claimant, class_name: 'Instructeur', optional: false has_one_attached :piece_justificative_file has_one_attached :introduction_file + has_one :expert, through: :experts_procedure validates :piece_justificative_file, content_type: AUTHORIZED_CONTENT_TYPES, diff --git a/app/models/experts_procedure.rb b/app/models/experts_procedure.rb index b8fa90b99..203f927fc 100644 --- a/app/models/experts_procedure.rb +++ b/app/models/experts_procedure.rb @@ -12,5 +12,6 @@ class ExpertsProcedure < ApplicationRecord belongs_to :expert belongs_to :procedure - validates :expert, uniqueness: { scope: :procedure } + + has_many :avis, dependent: :destroy end diff --git a/db/migrate/20210113084256_add_experts_procedure_to_avis.rb b/db/migrate/20210113084256_add_experts_procedure_to_avis.rb new file mode 100644 index 000000000..57abcfbe8 --- /dev/null +++ b/db/migrate/20210113084256_add_experts_procedure_to_avis.rb @@ -0,0 +1,5 @@ +class AddExpertsProcedureToAvis < ActiveRecord::Migration[6.0] + def change + add_reference :avis, :experts_procedure, foreign_key: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 26d4e415f..04d6c7d50 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_01_13_150013) do +ActiveRecord::Schema.define(version: 2021_01_13_084256) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -121,8 +121,10 @@ ActiveRecord::Schema.define(version: 2021_01_13_150013) do t.integer "claimant_id", null: false t.boolean "confidentiel", default: false, null: false t.datetime "revoked_at" + t.bigint "experts_procedure_id" t.index ["claimant_id"], name: "index_avis_on_claimant_id" t.index ["dossier_id"], name: "index_avis_on_dossier_id" + t.index ["experts_procedure_id"], name: "index_avis_on_experts_procedure_id" t.index ["instructeur_id"], name: "index_avis_on_instructeur_id" end @@ -723,6 +725,7 @@ ActiveRecord::Schema.define(version: 2021_01_13_150013) do add_foreign_key "assign_tos", "groupe_instructeurs" add_foreign_key "attestation_templates", "procedures" add_foreign_key "attestations", "dossiers" + add_foreign_key "avis", "experts_procedures" add_foreign_key "avis", "instructeurs", column: "claimant_id" add_foreign_key "champs", "champs", column: "parent_id" add_foreign_key "closed_mails", "procedures" From 2987139dd6a2ca4f618aace4cecaef556a8185f5 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Thu, 14 Jan 2021 20:07:31 +0100 Subject: [PATCH 07/17] Link avis to an expert --- app/controllers/concerns/create_avis_concern.rb | 5 ++++- spec/models/avis_spec.rb | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/create_avis_concern.rb b/app/controllers/concerns/create_avis_concern.rb index a88c2768b..ef54d7b2d 100644 --- a/app/controllers/concerns/create_avis_concern.rb +++ b/app/controllers/concerns/create_avis_concern.rb @@ -19,6 +19,8 @@ module CreateAvisConcern create_results = Avis.create( expert_emails.flat_map do |email| + expert = User.create_or_promote_to_expert(email, SecureRandom.hex).expert + experts_procedure = ExpertsProcedure.find_or_create_by(procedure: dossier.procedure, expert: expert) allowed_dossiers.map do |dossier| { email: email, @@ -26,7 +28,8 @@ module CreateAvisConcern introduction_file: create_avis_params[:introduction_file], claimant: current_instructeur, dossier: dossier, - confidentiel: confidentiel + confidentiel: confidentiel, + experts_procedure: experts_procedure } end end diff --git a/spec/models/avis_spec.rb b/spec/models/avis_spec.rb index 37c156cc5..2e66a90b2 100644 --- a/spec/models/avis_spec.rb +++ b/spec/models/avis_spec.rb @@ -56,6 +56,23 @@ RSpec.describe Avis, type: :model do end end + describe "an avis is linked to an expert_procedure" do + let(:procedure) { create(:procedure) } + let(:expert) { create(:expert) } + let(:experts_procedure) { ExpertsProcedure.create(procedure: procedure, expert: expert) } + + context 'an avis is linked to an experts_procedure' do + let!(:avis) { create(:avis, email: nil, experts_procedure: experts_procedure) } + + before do + avis.reload + end + + it { expect(avis.email).to be_nil } + it { expect(avis.experts_procedure).to eq(experts_procedure) } + end + end + describe '.avis_exists_and_email_belongs_to_avis?' do let(:dossier) { create(:dossier) } let(:invited_email) { 'invited@avis.com' } From b39d9d41f0d2b02614cf27edecef57cf274d84a3 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Tue, 19 Jan 2021 14:57:23 +0100 Subject: [PATCH 08/17] Add afterparty task to create experts from instructeurs after deploy --- db/schema.rb | 2 +- ...ll_experts_procedure_id_on_avis_table.rake | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 lib/tasks/deployment/20210118142539_backfill_experts_procedure_id_on_avis_table.rake diff --git a/db/schema.rb b/db/schema.rb index 04d6c7d50..64ad0784a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_01_13_084256) do +ActiveRecord::Schema.define(version: 2021_01_20_084256) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/tasks/deployment/20210118142539_backfill_experts_procedure_id_on_avis_table.rake b/lib/tasks/deployment/20210118142539_backfill_experts_procedure_id_on_avis_table.rake new file mode 100644 index 000000000..0deb5e4b8 --- /dev/null +++ b/lib/tasks/deployment/20210118142539_backfill_experts_procedure_id_on_avis_table.rake @@ -0,0 +1,28 @@ +namespace :after_party do + desc 'Deployment task: backfill_expert_id_on_avis_table' + task backfill_experts_procedure_id_on_avis_table: :environment do + puts "Running deploy task 'backfill_expert_id_on_avis_table'" + # rubocop:disable DS/Unscoped + # rubocop:disable Rails/PluckInWhere + + Instructeur.includes(:user) + .where(id: Avis.unscoped.pluck(:instructeur_id)) + .where.not(users: { instructeur_id: nil }) + .find_each do |instructeur| + user = instructeur.user + User.create_or_promote_to_expert(user.email, SecureRandom.hex) + user.reload + # rubocop:enable DS/Unscoped + # rubocop:enable Rails/PluckInWhere + instructeur.avis.each do |avis| + experts_procedure = ExpertsProcedure.find_or_create_by(expert: user.expert, procedure: avis.procedure) + avis.update_column(:experts_procedure_id, experts_procedure.id) + end + end + + # Update task as completed. If you remove the line below, the task will + # run with every deploy (or every time you call after_party:run). + AfterParty::TaskRecord + .create version: AfterParty::TaskRecorder.new(__FILE__).timestamp + end +end From f280820201466b72ba2f91e7360961ebf6bbe4dc Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Thu, 21 Jan 2021 14:57:57 +0100 Subject: [PATCH 09/17] Add unique index to Experts Procedures on expert <> procedure ids --- .../20210121134435_add_unique_index_to_experts_procedures.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20210121134435_add_unique_index_to_experts_procedures.rb diff --git a/db/migrate/20210121134435_add_unique_index_to_experts_procedures.rb b/db/migrate/20210121134435_add_unique_index_to_experts_procedures.rb new file mode 100644 index 000000000..965b5ba27 --- /dev/null +++ b/db/migrate/20210121134435_add_unique_index_to_experts_procedures.rb @@ -0,0 +1,5 @@ +class AddUniqueIndexToExpertsProcedures < ActiveRecord::Migration[6.0] + def change + add_index :experts_procedures, [:expert_id, :procedure_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 64ad0784a..46a02c5a3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_01_20_084256) do +ActiveRecord::Schema.define(version: 2021_01_21_134435) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -334,6 +334,7 @@ ActiveRecord::Schema.define(version: 2021_01_20_084256) do t.boolean "allow_decision_access", default: false, null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.index ["expert_id", "procedure_id"], name: "index_experts_procedures_on_expert_id_and_procedure_id", unique: true t.index ["expert_id"], name: "index_experts_procedures_on_expert_id" t.index ["procedure_id"], name: "index_experts_procedures_on_procedure_id" end From d8aaba9975bdd82a5fcde7de35ab9fb71a621fc9 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Mon, 25 Jan 2021 19:50:32 +0100 Subject: [PATCH 10/17] update entreprise annuaire link --- app/views/shared/dossiers/_identite_entreprise.html.haml | 4 ++-- .../users/dossiers/etablissement/_infos_entreprise.html.haml | 4 ++-- app/views/users/dossiers/siret.html.haml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/shared/dossiers/_identite_entreprise.html.haml b/app/views/shared/dossiers/_identite_entreprise.html.haml index 8371deffa..ef0b2aeee 100644 --- a/app/views/shared/dossiers/_identite_entreprise.html.haml +++ b/app/views/shared/dossiers/_identite_entreprise.html.haml @@ -145,6 +145,6 @@ %td= try_format_date(etablissement.association_date_declaration) %p - = link_to "➡ Autres informations sur l’organisme sur « entreprise.data.gouv.fr » (ex: fiche d'immatriculation RNCS)", - "https://entreprise.data.gouv.fr/etablissement/#{etablissement.siret}", + = link_to "➡ Autres informations sur l’organisme sur « annuaire-entreprises.data.gouv.fr » (ex: fiche d'immatriculation RNCS)", + "https://annuaire-entreprises.data.gouv.fr/entreprise/#{etablissement.siren}", target: "_blank" diff --git a/app/views/users/dossiers/etablissement/_infos_entreprise.html.haml b/app/views/users/dossiers/etablissement/_infos_entreprise.html.haml index 3e43095af..cf95693a9 100644 --- a/app/views/users/dossiers/etablissement/_infos_entreprise.html.haml +++ b/app/views/users/dossiers/etablissement/_infos_entreprise.html.haml @@ -30,6 +30,6 @@ - if procedure.api_entreprise_role?("bilans_bdf") %p.etablissement-exercices Les 3 derniers bilans connus de votre entreprise par la Banque de France ont été joints à votre dossier. %p - = link_to '➡ Autres informations sur l’organisme sur « entreprise.data.gouv.fr »', - "https://entreprise.data.gouv.fr/etablissement/#{etablissement.siret}", + = link_to "➡ Autres informations sur l’organisme sur « annuaire-entreprises.data.gouv.fr »", + "https://annuaire-entreprises.data.gouv.fr/entreprise/#{etablissement.siren}", target: "_blank" diff --git a/app/views/users/dossiers/siret.html.haml b/app/views/users/dossiers/siret.html.haml index 62735fd09..550c4518a 100644 --- a/app/views/users/dossiers/siret.html.haml +++ b/app/views/users/dossiers/siret.html.haml @@ -12,8 +12,8 @@ %p.mb-4 Pour trouver votre numéro SIRET, utilisez - %a{ href: 'https://entreprise.data.gouv.fr/', target: '_blank', rel: 'noopener' } - entreprise.data.gouv.fr + %a{ href: "https://annuaire-entreprises.data.gouv.fr" , target: '_blank', rel: 'noopener' } + annuaire-entreprises.data.gouv.fr ou renseignez-vous auprès de votre service comptable. = f.submit "Valider", class: "button large primary expand mt-1", data: { disable_with: "Récupération des informations…" } From 4452b2cf45a136304222d5fc43c630c46ac99c1a Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 20 Jan 2021 16:31:38 +0100 Subject: [PATCH 11/17] fix order of types de champ on procedure --- app/models/procedure.rb | 12 ++++++------ spec/models/procedure_revision_spec.rb | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/models/procedure.rb b/app/models/procedure.rb index eed64273b..d48f06111 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -62,13 +62,13 @@ class Procedure < ApplicationRecord belongs_to :published_revision, class_name: 'ProcedureRevision', optional: true has_many :deleted_dossiers, dependent: :destroy - has_many :published_types_de_champ, -> { ordered }, through: :published_revision, source: :types_de_champ - has_many :published_types_de_champ_private, -> { ordered }, through: :published_revision, source: :types_de_champ_private - has_many :draft_types_de_champ, -> { ordered }, through: :draft_revision, source: :types_de_champ - has_many :draft_types_de_champ_private, -> { ordered }, through: :draft_revision, source: :types_de_champ_private + has_many :published_types_de_champ, through: :published_revision, source: :types_de_champ + has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private + has_many :draft_types_de_champ, through: :draft_revision, source: :types_de_champ + has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private - has_many :all_types_de_champ, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id').ordered }, through: :revisions, source: :types_de_champ - has_many :all_types_de_champ_private, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id').ordered }, through: :revisions, source: :types_de_champ_private + has_many :all_types_de_champ, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id') }, through: :revisions, source: :types_de_champ + has_many :all_types_de_champ_private, -> { joins(:procedure).where('types_de_champ.revision_id != procedures.draft_revision_id') }, through: :revisions, source: :types_de_champ_private has_many :experts_procedures, dependent: :destroy has_many :experts, through: :experts_procedures diff --git a/spec/models/procedure_revision_spec.rb b/spec/models/procedure_revision_spec.rb index 7c3c39c79..be67e94c6 100644 --- a/spec/models/procedure_revision_spec.rb +++ b/spec/models/procedure_revision_spec.rb @@ -51,16 +51,22 @@ describe ProcedureRevision do it 'move down' do expect(revision.types_de_champ.index(type_de_champ)).to eq(0) + type_de_champ.update(order_place: nil) revision.move_type_de_champ(type_de_champ.stable_id, 2) revision.reload expect(revision.types_de_champ.index(type_de_champ)).to eq(2) + expect(revision.procedure.types_de_champ.index(type_de_champ)).to eq(2) + expect(revision.procedure.types_de_champ_for_export.index(type_de_champ)).to eq(2) end it 'move up' do expect(revision.types_de_champ.index(last_type_de_champ)).to eq(3) + last_type_de_champ.update(order_place: nil) revision.move_type_de_champ(last_type_de_champ.stable_id, 0) revision.reload expect(revision.types_de_champ.index(last_type_de_champ)).to eq(0) + expect(revision.procedure.types_de_champ.index(last_type_de_champ)).to eq(0) + expect(revision.procedure.types_de_champ_for_export.index(last_type_de_champ)).to eq(0) end context 'repetition' do From 85242e118b40a892d39f07a1d3a652bc438f8f9f Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Mon, 25 Jan 2021 13:01:13 +0100 Subject: [PATCH 12/17] add an email method to expert model --- app/models/expert.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/expert.rb b/app/models/expert.rb index 9564353cb..2e10b049e 100644 --- a/app/models/expert.rb +++ b/app/models/expert.rb @@ -8,4 +8,8 @@ # class Expert < ApplicationRecord has_one :user + + def email + user.email + end end From 9b8d2f6fd38dd6394e756e16310c05c2e3abdd89 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Mon, 25 Jan 2021 13:02:22 +0100 Subject: [PATCH 13/17] instead of call Avis table, we now call Experts Procedure table to see the experts list --- .../procedures_controller.rb | 2 +- app/models/avis.rb | 10 ----- app/models/experts_procedure.rb | 11 +++++ spec/models/avis_spec.rb | 42 ------------------- spec/models/experts_procedure_spec.rb | 42 +++++++++++++++++++ .../invited_expert_list.html.haml_spec.rb | 19 +++++---- 6 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 spec/models/experts_procedure_spec.rb diff --git a/app/controllers/new_administrateur/procedures_controller.rb b/app/controllers/new_administrateur/procedures_controller.rb index 2f250ae2e..1e74e2312 100644 --- a/app/controllers/new_administrateur/procedures_controller.rb +++ b/app/controllers/new_administrateur/procedures_controller.rb @@ -186,7 +186,7 @@ module NewAdministrateur end def invited_expert_list - @invited_expert_emails = Avis.invited_expert_emails(@procedure) + @invited_expert_emails = ExpertsProcedure.invited_expert_emails(@procedure) end private diff --git a/app/models/avis.rb b/app/models/avis.rb index a0d74704b..ba410c41f 100644 --- a/app/models/avis.rb +++ b/app/models/avis.rb @@ -67,16 +67,6 @@ class Avis < ApplicationRecord Avis.find_by(id: avis_id)&.email == email end - def self.invited_expert_emails(procedure) - Avis - .joins(dossier: :revision) - .left_joins(instructeur: :user) - .where(procedure_revisions: { procedure_id: procedure }) - .map(&:email_to_display) - .uniq - .sort - end - def spreadsheet_columns [ ['Dossier ID', dossier_id.to_s], diff --git a/app/models/experts_procedure.rb b/app/models/experts_procedure.rb index 203f927fc..d874fdb36 100644 --- a/app/models/experts_procedure.rb +++ b/app/models/experts_procedure.rb @@ -14,4 +14,15 @@ class ExpertsProcedure < ApplicationRecord belongs_to :procedure has_many :avis, dependent: :destroy + + def email_to_display + expert&.email + end + + def self.invited_expert_emails(procedure) + joins(:expert) + .where(procedure: procedure) + .map(&:email_to_display) + .sort + end end diff --git a/spec/models/avis_spec.rb b/spec/models/avis_spec.rb index 2e66a90b2..90f10ce76 100644 --- a/spec/models/avis_spec.rb +++ b/spec/models/avis_spec.rb @@ -217,46 +217,4 @@ RSpec.describe Avis, type: :model do end end end - - describe '#invited_expert_emails' do - let!(:procedure) { create(:procedure, :published) } - - subject { Avis.invited_expert_emails(procedure) } - - context 'when there is one dossier' do - let!(:dossier) { create(:dossier, procedure: procedure) } - - context 'when a procedure has one avis and unknown instructeur' do - let!(:avis) { create(:avis, dossier: dossier, email: 'expert@expert.com') } - - it { is_expected.to eq(['expert@expert.com']) } - end - - context 'when a procedure has one avis and known instructeur' do - let!(:avis) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: 'expert@expert.com')) } - - it { is_expected.to eq(['expert@expert.com']) } - end - - context 'when a dossier has 2 avis from the same expert' do - let!(:avis) { create(:avis, dossier: dossier, email: 'expert@expert.com') } - let!(:avis2) { create(:avis, dossier: dossier, email: 'expert@expert.com') } - - it { is_expected.to eq(['expert@expert.com']) } - end - end - - context 'when there are two dossiers' do - let!(:dossier) { create(:dossier, procedure: procedure) } - let!(:dossier2) { create(:dossier, procedure: procedure) } - - context 'and each one has an avis from 3 different experts' do - let!(:avis) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: '2_expert@expert.com')) } - let!(:unaffected_avis) { create(:avis, dossier: dossier2, email: '3_expert@expert.com') } - let!(:unaffected_avis2) { create(:avis, dossier: dossier2, email: '1_expert@expert.com') } - - it { is_expected.to eq(['1_expert@expert.com', '2_expert@expert.com', '3_expert@expert.com']) } - end - end - end end diff --git a/spec/models/experts_procedure_spec.rb b/spec/models/experts_procedure_spec.rb new file mode 100644 index 000000000..efd227593 --- /dev/null +++ b/spec/models/experts_procedure_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe ExpertsProcedure, type: :model do + describe '#invited_expert_emails' do + let!(:procedure) { create(:procedure, :published) } + let(:expert) { create(:expert) } + let(:expert2) { create(:expert) } + let(:expert3) { create(:expert) } + let(:experts_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) } + let(:experts_procedure2) { ExpertsProcedure.create(expert: expert2, procedure: procedure) } + let(:experts_procedure3) { ExpertsProcedure.create(expert: expert3, procedure: procedure) } + subject { ExpertsProcedure.invited_expert_emails(procedure) } + + context 'when there is one dossier' do + let!(:dossier) { create(:dossier, procedure: procedure) } + + context 'when a procedure has one avis and known instructeur' do + let!(:avis) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: expert.email), experts_procedure: experts_procedure) } + + it { is_expected.to eq([expert.email]) } + end + + context 'when a dossier has 2 avis from the same expert' do + let!(:avis) { create(:avis, dossier: dossier, experts_procedure: experts_procedure) } + let!(:avis2) { create(:avis, dossier: dossier, experts_procedure: experts_procedure) } + + it { is_expected.to eq([expert.email]) } + end + end + + context 'when there are two dossiers' do + let!(:dossier) { create(:dossier, procedure: procedure) } + let!(:dossier2) { create(:dossier, procedure: procedure) } + + context 'and each one has an avis from 3 different experts' do + let!(:avis) { create(:avis, dossier: dossier, experts_procedure: experts_procedure) } + let!(:avis2) { create(:avis, dossier: dossier2, experts_procedure: experts_procedure2) } + let!(:avis3) { create(:avis, dossier: dossier2, experts_procedure: experts_procedure3) } + + it { is_expected.to eq([expert.email, expert2.email, expert3.email].sort) } + end + end + end +end diff --git a/spec/views/new_administrateur/procedures/invited_expert_list.html.haml_spec.rb b/spec/views/new_administrateur/procedures/invited_expert_list.html.haml_spec.rb index ff575ed94..675353a80 100644 --- a/spec/views/new_administrateur/procedures/invited_expert_list.html.haml_spec.rb +++ b/spec/views/new_administrateur/procedures/invited_expert_list.html.haml_spec.rb @@ -12,7 +12,7 @@ describe 'new_administrateur/procedures/invited_expert_list.html.haml', type: :v context 'when the procedure has 0 avis' do let!(:dossier) { create(:dossier, procedure: procedure) } before do - @invited_expert_emails = Avis.invited_expert_emails(procedure) + @invited_expert_emails = ExpertsProcedure.invited_expert_emails(procedure) subject end @@ -24,18 +24,21 @@ describe 'new_administrateur/procedures/invited_expert_list.html.haml', type: :v context 'when the procedure has 3 avis from 2 experts and 1 unasigned' do let!(:dossier) { create(:dossier, procedure: procedure) } - let!(:avis) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: '1_expert@expert.com')) } - let!(:avis2) { create(:avis, dossier: dossier, instructeur: create(:instructeur, email: '2_expert@expert.com')) } - let!(:unasigned_avis) { create(:avis, dossier: dossier, email: 'expert@expert.com') } + let(:expert) { create(:expert) } + let(:expert2) { create(:expert) } + let(:experts_procedure) { ExpertsProcedure.create(procedure: procedure, expert: expert) } + let(:experts_procedure2) { ExpertsProcedure.create(procedure: procedure, expert: expert2) } + let!(:avis) { create(:avis, dossier: dossier, experts_procedure: experts_procedure) } + let!(:avis2) { create(:avis, dossier: dossier, experts_procedure: experts_procedure2) } before do - @invited_expert_emails = Avis.invited_expert_emails(procedure) + @invited_expert_emails = ExpertsProcedure.invited_expert_emails(procedure) subject end - it 'has 3 experts and match array' do - expect(@invited_expert_emails.count).to eq(3) - expect(@invited_expert_emails).to eq(['1_expert@expert.com', '2_expert@expert.com', 'expert@expert.com']) + it 'has 2 experts and match array' do + expect(@invited_expert_emails.count).to eq(2) + expect(@invited_expert_emails).to eq([expert.email, expert2.email]) end end end From 96f8b9e2bf436978339f174cd85fa8637133a564 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 26 Jan 2021 12:36:10 +0100 Subject: [PATCH 14/17] Enforce siret validity for champ siret --- app/controllers/champs/siret_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/champs/siret_controller.rb b/app/controllers/champs/siret_controller.rb index 8d0183380..6f1a5a4e4 100644 --- a/app/controllers/champs/siret_controller.rb +++ b/app/controllers/champs/siret_controller.rb @@ -10,7 +10,7 @@ class Champs::SiretController < ApplicationController return clear_siret_and_etablissement end - if @siret.present? && @siret.length != 14 + if !Siret.new(siret: @siret).valid? return siret_error(:invalid) end From 03ddd17884e73eaf549884afb25ac23c319a113a Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 26 Jan 2021 14:31:01 +0100 Subject: [PATCH 15/17] Ignore entreprise_id on etablissements --- app/models/etablissement.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/etablissement.rb b/app/models/etablissement.rb index d4916c087..c4532915c 100644 --- a/app/models/etablissement.rb +++ b/app/models/etablissement.rb @@ -48,6 +48,8 @@ # entreprise_id :integer # class Etablissement < ApplicationRecord + self.ignored_columns = [:entreprise_id] + belongs_to :dossier, optional: true has_one :champ, class_name: 'Champs::SiretChamp' From a26537c77d077bdbb859e2727c1d0981aadab620 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 26 Jan 2021 14:32:34 +0100 Subject: [PATCH 16/17] Make some api entreprise fields optional --- app/graphql/schema.graphql | 8 ++++---- app/graphql/types/personne_morale_type.rb | 8 ++++---- app/models/entreprise.rb | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 357922337..8e1db6da2 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -803,13 +803,13 @@ type Entreprise { effectif pour un mois donné """ effectifMensuel: Effectif - formeJuridique: String! - formeJuridiqueCode: String! + formeJuridique: String + formeJuridiqueCode: String inlineAdresse: String! - nom: String! + nom: String nomCommercial: String! numeroTvaIntracommunautaire: String! - prenom: String! + prenom: String raisonSociale: String! siren: String! siretSiegeSocial: String! diff --git a/app/graphql/types/personne_morale_type.rb b/app/graphql/types/personne_morale_type.rb index 2a74a0cea..c84f0925d 100644 --- a/app/graphql/types/personne_morale_type.rb +++ b/app/graphql/types/personne_morale_type.rb @@ -9,8 +9,8 @@ module Types field :siren, String, null: false field :capital_social, GraphQL::Types::BigInt, null: false, description: "capital social de l’entreprise. -1 si inconnu." field :numero_tva_intracommunautaire, String, null: false - field :forme_juridique, String, null: false - field :forme_juridique_code, String, null: false + field :forme_juridique, String, null: true + field :forme_juridique_code, String, null: true field :nom_commercial, String, null: false field :raison_sociale, String, null: false field :siret_siege_social, String, null: false @@ -18,8 +18,8 @@ module Types field :effectif_mensuel, EffectifType, null: true, description: "effectif pour un mois donné" field :effectif_annuel, EffectifType, null: true, description: "effectif moyen d’une année" field :date_creation, GraphQL::Types::ISO8601Date, null: false - field :nom, String, null: false - field :prenom, String, null: false + field :nom, String, null: true + field :prenom, String, null: true field :inline_adresse, String, null: false field :attestation_sociale_attachment, Types::File, null: true field :attestation_fiscale_attachment, Types::File, null: true diff --git a/app/models/entreprise.rb b/app/models/entreprise.rb index 3b471cbaf..366a695f5 100644 --- a/app/models/entreprise.rb +++ b/app/models/entreprise.rb @@ -7,8 +7,8 @@ class Entreprise < Hashie::Dash property :siren property :capital_social property :numero_tva_intracommunautaire - property :forme_juridique - property :forme_juridique_code + property :forme_juridique, default: nil + property :forme_juridique_code, default: nil property :nom_commercial property :raison_sociale property :siret_siege_social @@ -19,8 +19,8 @@ class Entreprise < Hashie::Dash property :effectif_annuel property :effectif_annuel_annee property :date_creation - property :nom - property :prenom + property :nom, default: nil + property :prenom, default: nil property :inline_adresse end From 1bba12dc3adb1f7109db9eb8e07d44bb3ed5975e Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 26 Jan 2021 13:30:16 +0100 Subject: [PATCH 17/17] Make some annuaire education fields optional --- app/schemas/etablissement-annuaire-education.json | 2 -- .../shared/champs/annuaire_education/_show.html.haml | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/schemas/etablissement-annuaire-education.json b/app/schemas/etablissement-annuaire-education.json index 704776700..2adce12ff 100644 --- a/app/schemas/etablissement-annuaire-education.json +++ b/app/schemas/etablissement-annuaire-education.json @@ -167,11 +167,9 @@ "required": [ "identifiant_de_l_etablissement", "nom_etablissement", - "statut_public_prive", "type_contrat_prive", "nom_commune", "code_commune", - "nombre_d_eleves", "siren_siret", "libelle_academie", "code_academie", diff --git a/app/views/shared/champs/annuaire_education/_show.html.haml b/app/views/shared/champs/annuaire_education/_show.html.haml index 5436a8ad2..baed3184d 100644 --- a/app/views/shared/champs/annuaire_education/_show.html.haml +++ b/app/views/shared/champs/annuaire_education/_show.html.haml @@ -25,9 +25,11 @@ %tr %th.libelle Type de contrat privé : %td= champ.data['type_contrat_prive'] - %tr - %th.libelle Nombre d’élèves : - %td= champ.data['nombre_d_eleves'] + + - if champ.data['nombre_d_eleves'].present? + %tr + %th.libelle Nombre d’élèves : + %td= champ.data['nombre_d_eleves'] %tr %th.libelle Adresse :