Merge pull request #3060 from tchak/dossier-state-change-logs

Dossier state change logs
This commit is contained in:
Paul Chavard 2018-11-27 13:02:46 +01:00 committed by GitHub
commit b53d7d5fef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 181 additions and 78 deletions

View file

@ -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 }

View file

@ -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

View file

@ -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}\""

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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