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 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/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/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/avis.rb b/app/models/avis.rb index 62d89b8ad..ba410c41f 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, @@ -64,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/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 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' diff --git a/app/models/expert.rb b/app/models/expert.rb new file mode 100644 index 000000000..2e10b049e --- /dev/null +++ b/app/models/expert.rb @@ -0,0 +1,15 @@ +# == 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 + + def email + user.email + end +end diff --git a/app/models/experts_procedure.rb b/app/models/experts_procedure.rb new file mode 100644 index 000000000..d874fdb36 --- /dev/null +++ b/app/models/experts_procedure.rb @@ -0,0 +1,28 @@ +# == 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 + + 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/app/models/procedure.rb b/app/models/procedure.rb index 4055bb7c9..d48f06111 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -62,13 +62,16 @@ 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 has_one :module_api_carto, dependent: :destroy has_one :attestation_template, dependent: :destroy diff --git a/app/models/user.rb b/app/models/user.rb index d1356face..d2a449528 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 @@ -128,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/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 : 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…" } 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/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/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/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 d32d42068..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_14_224721) 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" @@ -121,8 +121,10 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) 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 @@ -321,6 +323,22 @@ 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 "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", "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 + create_table "exports", force: :cascade do |t| t.string "format", null: false t.datetime "created_at", null: false @@ -676,9 +694,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 @@ -706,6 +726,7 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) 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" @@ -715,6 +736,8 @@ ActiveRecord::Schema.define(version: 2021_01_14_224721) 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" @@ -734,6 +757,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 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 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/avis_spec.rb b/spec/models/avis_spec.rb index 37c156cc5..90f10ce76 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' } @@ -200,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/expert_spec.rb b/spec/models/expert_spec.rb new file mode 100644 index 000000000..2b3dd1c78 --- /dev/null +++ b/spec/models/expert_spec.rb @@ -0,0 +1,15 @@ +RSpec.describe Expert, type: :model do + describe 'an expert could be add to a procedure' do + let(:procedure) { create(:procedure) } + let(:expert) { create(:expert) } + + before do + procedure.experts << expert + procedure.reload + 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 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/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 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) } 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