diff --git a/app/controllers/new_gestionnaire/dossiers_controller.rb b/app/controllers/new_gestionnaire/dossiers_controller.rb index 47aafc301..473d66d08 100644 --- a/app/controllers/new_gestionnaire/dossiers_controller.rb +++ b/app/controllers/new_gestionnaire/dossiers_controller.rb @@ -74,44 +74,32 @@ module NewGestionnaire end def passer_en_instruction - dossier.en_instruction! - current_gestionnaire.follow(dossier) + dossier.passer_en_instruction!(current_gestionnaire) flash.notice = 'Dossier passé en instruction.' render partial: 'state_button_refresh', locals: { dossier: dossier } end def repasser_en_construction - dossier.en_construction! + dossier.repasser_en_construction!(current_gestionnaire) flash.notice = 'Dossier repassé en construction.' render partial: 'state_button_refresh', locals: { dossier: dossier } end def terminer - if params[:dossier] && params[:dossier][:motivation].present? - dossier.motivation = params[:dossier][:motivation] - end + motivation = params[:dossier] && params[:dossier][:motivation] case params[:process_action] when "refuser" - dossier.refuse! - dossier.save + dossier.refuser!(current_gestionnaire, motivation) flash.notice = "Dossier considéré comme refusé." - NotificationMailer.send_refused_notification(dossier).deliver_later when "classer_sans_suite" - dossier.sans_suite! - dossier.save + dossier.classer_sans_suite!(current_gestionnaire, motivation) flash.notice = "Dossier considéré comme sans suite." - NotificationMailer.send_without_continuation_notification(dossier).deliver_later when "accepter" - dossier.accepte! - if dossier.attestation.nil? - dossier.attestation = dossier.build_attestation - dossier.save - end + dossier.accepter!(current_gestionnaire, motivation) flash.notice = "Dossier traité avec succès." - NotificationMailer.send_closed_notification(dossier).deliver_later end render partial: 'state_button_refresh', locals: { dossier: dossier } diff --git a/app/jobs/auto_archive_procedure_job.rb b/app/jobs/auto_archive_procedure_job.rb index 0821ba5ed..7791dbc13 100644 --- a/app/jobs/auto_archive_procedure_job.rb +++ b/app/jobs/auto_archive_procedure_job.rb @@ -3,7 +3,11 @@ class AutoArchiveProcedureJob < ApplicationJob def perform(*args) Procedure.publiees.where("auto_archive_on <= ?", Date.today).each do |procedure| - procedure.dossiers.state_en_construction.each(&:en_instruction!) + gestionnaire = procedure.gestionnaire_for_cron_job + + procedure.dossiers.state_en_construction.find_each do |dossier| + dossier.passer_en_instruction!(gestionnaire) + end procedure.archive! end diff --git a/app/jobs/auto_receive_dossiers_for_procedure_job.rb b/app/jobs/auto_receive_dossiers_for_procedure_job.rb index ce44c4d46..6ff7fa117 100644 --- a/app/jobs/auto_receive_dossiers_for_procedure_job.rb +++ b/app/jobs/auto_receive_dossiers_for_procedure_job.rb @@ -1,24 +1,18 @@ class AutoReceiveDossiersForProcedureJob < ApplicationJob queue_as :cron - def perform(procedure_id, state) + def perform(procedure_id, state, gestionnaire_id = nil) procedure = Procedure.find(procedure_id) + gestionnaire = procedure.gestionnaire_for_cron_job + case state when Dossier.states.fetch(:en_instruction) - procedure.dossiers.state_en_construction.update_all( - state: Dossier.states.fetch(:en_instruction), - en_instruction_at: Time.zone.now - ) + procedure.dossiers.state_en_construction.find_each do |dossier| + dossier.passer_en_instruction!(gestionnaire) + end when Dossier.states.fetch(:accepte) procedure.dossiers.state_en_construction.find_each do |dossier| - dossier.update( - state: Dossier.states.fetch(:accepte), - en_instruction_at: Time.zone.now, - processed_at: Time.zone.now - ) - dossier.attestation = dossier.build_attestation - dossier.save - NotificationMailer.send_closed_notification(dossier).deliver_later + dossier.accepter!(gestionnaire, '') end else raise "Receiving Procedure##{procedure_id} in invalid state \"#{state}\"" diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 22f3cfe4c..d5d6273c8 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -28,6 +28,8 @@ class Dossier < ApplicationRecord has_many :followers_gestionnaires, through: :follows, source: :gestionnaire has_many :avis, dependent: :destroy + has_many :dossier_operation_logs + belongs_to :procedure belongs_to :user @@ -306,8 +308,63 @@ class Dossier < ApplicationRecord DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later end + def passer_en_instruction!(gestionnaire) + en_instruction! + gestionnaire.follow(self) + + log_dossier_operation(gestionnaire, :passer_en_instruction) + end + + def repasser_en_construction!(gestionnaire) + self.en_instruction_at = nil + en_construction! + + log_dossier_operation(gestionnaire, :repasser_en_construction) + end + + def accepter!(gestionnaire, motivation) + self.motivation = motivation + self.en_instruction_at ||= Time.zone.now + + accepte! + + if attestation.nil? + update(attestation: build_attestation) + end + + NotificationMailer.send_closed_notification(self).deliver_later + log_dossier_operation(gestionnaire, :accepter) + end + + def refuser!(gestionnaire, motivation) + self.motivation = motivation + self.en_instruction_at ||= Time.zone.now + + refuse! + + NotificationMailer.send_refused_notification(self).deliver_later + log_dossier_operation(gestionnaire, :refuser) + end + + def classer_sans_suite!(gestionnaire, motivation) + self.motivation = motivation + self.en_instruction_at ||= Time.zone.now + + sans_suite! + + NotificationMailer.send_without_continuation_notification(self).deliver_later + log_dossier_operation(gestionnaire, :classer_sans_suite) + end + private + def log_dossier_operation(gestionnaire, operation) + dossier_operation_logs.create( + gestionnaire: gestionnaire, + operation: DossierOperationLog.operations.fetch(operation) + ) + end + def update_state_dates if en_construction? && !self.en_construction_at self.en_construction_at = Time.zone.now diff --git a/app/models/dossier_operation_log.rb b/app/models/dossier_operation_log.rb new file mode 100644 index 000000000..fd4e770a4 --- /dev/null +++ b/app/models/dossier_operation_log.rb @@ -0,0 +1,12 @@ +class DossierOperationLog < ApplicationRecord + enum operation: { + passer_en_instruction: 'passer_en_instruction', + repasser_en_construction: 'repasser_en_construction', + accepter: 'accepter', + refuser: 'refuser', + classer_sans_suite: 'classer_sans_suite' + } + + belongs_to :dossier + belongs_to :gestionnaire +end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 2ad171a4c..2021d69b2 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -358,6 +358,12 @@ class Procedure < ApplicationRecord where.not(aasm_state: :archivee).where("path LIKE ?", "%#{path}%") end + def gestionnaire_for_cron_job + administrateur_email = administrateur.email + gestionnaire = Gestionnaire.find_by(email: administrateur_email) + gestionnaire || gestionnaires.first + end + private def claim_path_ownership!(path) diff --git a/db/migrate/20181123195208_create_dossier_operation_logs.rb b/db/migrate/20181123195208_create_dossier_operation_logs.rb new file mode 100644 index 000000000..7a6003219 --- /dev/null +++ b/db/migrate/20181123195208_create_dossier_operation_logs.rb @@ -0,0 +1,11 @@ +class CreateDossierOperationLogs < ActiveRecord::Migration[5.2] + def change + create_table :dossier_operation_logs do |t| + t.string :operation, null: false + t.references :dossier, foreign_key: true, index: true + t.references :gestionnaire, foreign_key: true, index: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 41ef703c6..b8b98f83e 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: 2018_11_21_234008) do +ActiveRecord::Schema.define(version: 2018_11_23_195208) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -218,6 +218,16 @@ ActiveRecord::Schema.define(version: 2018_11_21_234008) do t.index ["procedure_id"], name: "index_deleted_dossiers_on_procedure_id" end + create_table "dossier_operation_logs", force: :cascade do |t| + t.string "operation", null: false + t.bigint "dossier_id" + t.bigint "gestionnaire_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["dossier_id"], name: "index_dossier_operation_logs_on_dossier_id" + t.index ["gestionnaire_id"], name: "index_dossier_operation_logs_on_gestionnaire_id" + end + create_table "dossiers", id: :serial, force: :cascade do |t| t.boolean "autorisation_donnees" t.integer "procedure_id" @@ -608,6 +618,8 @@ ActiveRecord::Schema.define(version: 2018_11_21_234008) do add_foreign_key "avis", "gestionnaires", column: "claimant_id" add_foreign_key "closed_mails", "procedures" add_foreign_key "commentaires", "dossiers" + add_foreign_key "dossier_operation_logs", "dossiers" + add_foreign_key "dossier_operation_logs", "gestionnaires" add_foreign_key "dossiers", "users" add_foreign_key "feedbacks", "users" add_foreign_key "geo_areas", "champs" diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index c22488dcc..7206a4504 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -46,6 +46,12 @@ FactoryBot.define do end end + trait :with_gestionnaire do + after(:build) do |procedure, _evaluator| + procedure.gestionnaires << create(:gestionnaire) + end + end + trait :with_api_carto do after(:build) do |procedure, _evaluator| procedure.module_api_carto.use_api_carto = true diff --git a/spec/jobs/auto_archive_procedure_job_spec.rb b/spec/jobs/auto_archive_procedure_job_spec.rb index d671ad212..3d3b58b05 100644 --- a/spec/jobs/auto_archive_procedure_job_spec.rb +++ b/spec/jobs/auto_archive_procedure_job_spec.rb @@ -1,10 +1,10 @@ require 'rails_helper' RSpec.describe AutoArchiveProcedureJob, type: :job do - let!(:procedure) { create(:procedure, :published, auto_archive_on: nil) } - let!(:procedure_hier) { create(:procedure, :published, auto_archive_on: 1.day.ago) } - let!(:procedure_aujourdhui) { create(:procedure, :published, auto_archive_on: Date.today) } - let!(:procedure_demain) { create(:procedure, :published, auto_archive_on: 1.day.from_now) } + let!(:procedure) { create(:procedure, :published, :with_gestionnaire, auto_archive_on: nil) } + let!(:procedure_hier) { create(:procedure, :published, :with_gestionnaire, auto_archive_on: 1.day.ago) } + let!(:procedure_aujourdhui) { create(:procedure, :published, :with_gestionnaire, auto_archive_on: Date.today) } + let!(:procedure_demain) { create(:procedure, :published, :with_gestionnaire, auto_archive_on: 1.day.from_now) } subject { AutoArchiveProcedureJob.new.perform } @@ -37,18 +37,22 @@ RSpec.describe AutoArchiveProcedureJob, type: :job do procedure_aujourdhui.reload end - it { expect(dossier1.state).to eq Dossier.states.fetch(:brouillon) } - it { expect(dossier2.state).to eq Dossier.states.fetch(:en_instruction) } - it { expect(dossier3.state).to eq Dossier.states.fetch(:en_instruction) } - it { expect(dossier4.state).to eq Dossier.states.fetch(:en_instruction) } - it { expect(dossier5.state).to eq Dossier.states.fetch(:en_instruction) } - it { expect(dossier6.state).to eq Dossier.states.fetch(:accepte) } - it { expect(dossier7.state).to eq Dossier.states.fetch(:refuse) } - it { expect(dossier8.state).to eq Dossier.states.fetch(:sans_suite) } - it { expect(dossier9.state).to eq Dossier.states.fetch(:en_instruction) } + it { + expect(dossier1.state).to eq Dossier.states.fetch(:brouillon) + expect(dossier2.state).to eq Dossier.states.fetch(:en_instruction) + expect(dossier3.state).to eq Dossier.states.fetch(:en_instruction) + expect(dossier4.state).to eq Dossier.states.fetch(:en_instruction) + expect(dossier5.state).to eq Dossier.states.fetch(:en_instruction) + expect(dossier6.state).to eq Dossier.states.fetch(:accepte) + expect(dossier7.state).to eq Dossier.states.fetch(:refuse) + expect(dossier8.state).to eq Dossier.states.fetch(:sans_suite) + expect(dossier9.state).to eq Dossier.states.fetch(:en_instruction) + } - it { expect(procedure_hier.archivee?).to eq true } - it { expect(procedure_aujourdhui.archivee?).to eq true } + it { + expect(procedure_hier.archivee?).to eq true + expect(procedure_aujourdhui.archivee?).to eq true + } end context "when procedures have auto_archive_on set on future" do diff --git a/spec/jobs/auto_receive_dossiers_for_procedure_job_spec.rb b/spec/jobs/auto_receive_dossiers_for_procedure_job_spec.rb index fa22ab6b5..ae4e06676 100644 --- a/spec/jobs/auto_receive_dossiers_for_procedure_job_spec.rb +++ b/spec/jobs/auto_receive_dossiers_for_procedure_job_spec.rb @@ -5,57 +5,66 @@ RSpec.describe AutoReceiveDossiersForProcedureJob, type: :job do let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) } let(:instruction_date) { date + 120 } + let(:procedure) { create(:procedure, :with_gestionnaire) } + let(:nouveau_dossier1) { create(:dossier, :en_construction, procedure: procedure) } + let(:nouveau_dossier2) { create(:dossier, :en_construction, procedure: procedure) } + let(:dossier_recu) { create(:dossier, :en_instruction, procedure: procedure) } + let(:dossier_brouillon) { create(:dossier, procedure: procedure) } + before do Timecop.freeze(date) - create(:attestation_template, procedure: nouveau_dossier1.procedure) - AutoReceiveDossiersForProcedureJob.new.perform(procedure_id, state) + nouveau_dossier1 + nouveau_dossier2 + dossier_recu + dossier_brouillon + + create(:attestation_template, procedure: procedure) + AutoReceiveDossiersForProcedureJob.new.perform(procedure.id, state) end after { Timecop.return } context "with some dossiers" do - let(:nouveau_dossier1) { create(:dossier, :en_construction) } - let(:nouveau_dossier2) { create(:dossier, :en_construction, procedure: nouveau_dossier1.procedure) } - let(:dossier_recu) { create(:dossier, :en_instruction, procedure: nouveau_dossier2.procedure) } - let(:dossier_brouillon) { create(:dossier, procedure: dossier_recu.procedure) } - let(:procedure_id) { dossier_brouillon.procedure_id } - context "en_construction" do let(:state) { Dossier.states.fetch(:en_instruction) } - it { expect(nouveau_dossier1.reload.en_instruction?).to be true } - it { expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) } + it { + expect(nouveau_dossier1.reload.en_instruction?).to be true + expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) - it { expect(nouveau_dossier2.reload.en_instruction?).to be true } - it { expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) } + expect(nouveau_dossier2.reload.en_instruction?).to be true + expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) - it { expect(dossier_recu.reload.en_instruction?).to be true } - it { expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) } + expect(dossier_recu.reload.en_instruction?).to be true + expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) - it { expect(dossier_brouillon.reload.brouillon?).to be true } - it { expect(dossier_brouillon.reload.en_instruction_at).to eq(nil) } + expect(dossier_brouillon.reload.brouillon?).to be true + expect(dossier_brouillon.reload.en_instruction_at).to eq(nil) + } end context "accepte" do let(:state) { Dossier.states.fetch(:accepte) } - it { expect(nouveau_dossier1.reload.accepte?).to be true } - it { expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) } - it { expect(nouveau_dossier1.reload.processed_at).to eq(date) } - it { expect(nouveau_dossier1.reload.attestation).to be_present } + it { + expect(nouveau_dossier1.reload.accepte?).to be true + expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) + expect(nouveau_dossier1.reload.processed_at).to eq(date) + expect(nouveau_dossier1.reload.attestation).to be_present - it { expect(nouveau_dossier2.reload.accepte?).to be true } - it { expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) } - it { expect(nouveau_dossier2.reload.processed_at).to eq(date) } - it { expect(nouveau_dossier2.reload.attestation).to be_present } + expect(nouveau_dossier2.reload.accepte?).to be true + expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) + expect(nouveau_dossier2.reload.processed_at).to eq(date) + expect(nouveau_dossier2.reload.attestation).to be_present - it { expect(dossier_recu.reload.en_instruction?).to be true } - it { expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) } - it { expect(dossier_recu.reload.processed_at).to eq(nil) } + expect(dossier_recu.reload.en_instruction?).to be true + expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) + expect(dossier_recu.reload.processed_at).to eq(nil) - it { expect(dossier_brouillon.reload.brouillon?).to be true } - it { expect(dossier_brouillon.reload.en_instruction_at).to eq(nil) } - it { expect(dossier_brouillon.reload.processed_at).to eq(nil) } + expect(dossier_brouillon.reload.brouillon?).to be true + expect(dossier_brouillon.reload.en_instruction_at).to eq(nil) + expect(dossier_brouillon.reload.processed_at).to eq(nil) + } end end end