feat(attestation): revise attestations

This commit is contained in:
Paul Chavard 2022-01-12 16:23:29 +01:00
parent c1cb89bb44
commit e413872530
13 changed files with 94 additions and 44 deletions

View file

@ -3,12 +3,17 @@ module Administrateurs
before_action :retrieve_procedure before_action :retrieve_procedure
def edit def edit
@attestation_template = @procedure.attestation_template || AttestationTemplate.new(procedure: @procedure) @attestation_template = build_attestation
end end
def update def update
attestation_template = @procedure.attestation_template attestation_template = @procedure.draft_attestation_template.revise!
if attestation_template.update(activated_attestation_params) if attestation_template.update(activated_attestation_params)
AttestationTemplate
.where(id: @procedure.revisions.pluck(:attestation_template_id).compact)
.update_all(activated: attestation_template.activated?)
flash.notice = "L'attestation a bien été modifiée" flash.notice = "L'attestation a bien été modifiée"
else else
flash.alert = attestation_template.errors.full_messages.join('<br>') flash.alert = attestation_template.errors.full_messages.join('<br>')
@ -18,7 +23,7 @@ module Administrateurs
end end
def create def create
attestation_template = AttestationTemplate.new(activated_attestation_params.merge(procedure_id: @procedure.id)) attestation_template = build_attestation(activated_attestation_params)
if attestation_template.save if attestation_template.save
flash.notice = "L'attestation a bien été sauvegardée" flash.notice = "L'attestation a bien été sauvegardée"
@ -30,14 +35,19 @@ module Administrateurs
end end
def preview def preview
attestation = @procedure.attestation_template || AttestationTemplate.new @attestation = build_attestation.render_attributes_for({})
@attestation = attestation.render_attributes_for({})
render 'administrateurs/attestation_templates/show', formats: [:pdf] render 'administrateurs/attestation_templates/show', formats: [:pdf]
end end
private private
def build_attestation(attributes = {})
attestation_template = @procedure.draft_attestation_template || @procedure.draft_revision.build_attestation_template
attestation_template.attributes = attributes
attestation_template
end
def activated_attestation_params def activated_attestation_params
# cache result to avoid multiple uninterlaced computations # cache result to avoid multiple uninterlaced computations
if @activated_attestation_params.nil? if @activated_attestation_params.nil?

View file

@ -15,7 +15,8 @@ class AttestationTemplate < ApplicationRecord
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
include TagsSubstitutionConcern include TagsSubstitutionConcern
belongs_to :procedure, optional: false belongs_to :procedure, optional: true
has_many :revisions, class_name: 'ProcedureRevision', inverse_of: :attestation_template, dependent: :nullify
has_one_attached :logo has_one_attached :logo
has_one_attached :signature has_one_attached :signature
@ -103,6 +104,25 @@ class AttestationTemplate < ApplicationRecord
} }
end end
def revise!
if revisions.size > 1
attestation_template = dup
attestation_template.save!
revisions
.last
.procedure
.draft_revision
.update!(attestation_template: attestation_template)
attestation_template
else
self
end
end
def procedure
revisions.last&.procedure || super
end
private private
def used_tags def used_tags

View file

@ -720,9 +720,11 @@ class Dossier < ApplicationRecord
{ lon: lon, lat: lat, zoom: zoom } { lon: lon, lat: lat, zoom: zoom }
end end
def unspecified_attestation_champs def attestation_template
attestation_template = procedure.attestation_template revision.attestation_template
end
def unspecified_attestation_champs
if attestation_template&.activated? if attestation_template&.activated?
attestation_template.unspecified_champs_for_dossier(self) attestation_template.unspecified_champs_for_dossier(self)
else else
@ -731,8 +733,8 @@ class Dossier < ApplicationRecord
end end
def build_attestation def build_attestation
if procedure.attestation_template&.activated? if attestation_template&.activated?
procedure.attestation_template.attestation_for(self) attestation_template.attestation_for(self)
end end
end end

View file

@ -77,12 +77,15 @@ class Procedure < ApplicationRecord
has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private 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, through: :draft_revision, source: :types_de_champ
has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private
has_one :draft_attestation_template, through: :draft_revision, source: :attestation_template
has_one :published_attestation_template, through: :published_revision, source: :attestation_template
has_many :experts_procedures, dependent: :destroy has_many :experts_procedures, dependent: :destroy
has_many :experts, through: :experts_procedures has_many :experts, through: :experts_procedures
has_one :module_api_carto, dependent: :destroy has_one :module_api_carto, dependent: :destroy
has_one :attestation_template, dependent: :destroy has_one :attestation_template, dependent: :destroy
has_many :attestation_templates, through: :revisions, source: :attestation_template
belongs_to :parent_procedure, class_name: 'Procedure', optional: true belongs_to :parent_procedure, class_name: 'Procedure', optional: true
belongs_to :canonical_procedure, class_name: 'Procedure', optional: true belongs_to :canonical_procedure, class_name: 'Procedure', optional: true
@ -434,7 +437,8 @@ class Procedure < ApplicationRecord
}, },
revision_types_de_champ_private: { revision_types_de_champ_private: {
type_de_champ: :types_de_champ type_de_champ: :types_de_champ
} },
attestation_template: []
} }
} }
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
@ -572,13 +576,17 @@ class Procedure < ApplicationRecord
touch(:whitelisted_at) touch(:whitelisted_at)
end end
def active_attestation_template
published_attestation_template || draft_attestation_template
end
def closed_mail_template_attestation_inconsistency_state def closed_mail_template_attestation_inconsistency_state
# As an optimization, dont check the predefined templates (they are presumed correct) # As an optimization, dont check the predefined templates (they are presumed correct)
if closed_mail.present? if closed_mail.present?
tag_present = closed_mail.body.to_s.include?("--lien attestation--") tag_present = closed_mail.body.to_s.include?("--lien attestation--")
if attestation_template&.activated? && !tag_present if active_attestation_template&.activated? && !tag_present
:missing_tag :missing_tag
elsif !attestation_template&.activated? && tag_present elsif !active_attestation_template&.activated? && tag_present
:extraneous_tag :extraneous_tag
end end
end end

View file

@ -2,15 +2,17 @@
# #
# Table name: procedure_revisions # Table name: procedure_revisions
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# published_at :datetime # published_at :datetime
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# procedure_id :bigint not null # attestation_template_id :bigint
# procedure_id :bigint not null
# #
class ProcedureRevision < ApplicationRecord class ProcedureRevision < ApplicationRecord
self.implicit_order_column = :created_at self.implicit_order_column = :created_at
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
belongs_to :attestation_template, inverse_of: :revisions, optional: true, dependent: :destroy
has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id
@ -125,6 +127,10 @@ class ProcedureRevision < ApplicationRecord
) )
end end
def attestation_template
super || procedure.attestation_template
end
private private
def compare_types_de_champ(from_tdc, to_tdc) def compare_types_de_champ(from_tdc, to_tdc)

View file

@ -138,7 +138,7 @@
.procedure-grid .procedure-grid
= link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'card-admin' do = link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'card-admin' do
- if @procedure.attestation_template.present? && @procedure.attestation_template.activated - if @procedure.draft_attestation_template&.activated?
%div %div
%span.icon.accept %span.icon.accept
%p.card-admin-status-accept Activée %p.card-admin-status-accept Activée

View file

@ -0,0 +1,5 @@
class AddAttestationTemplateIdToProcedureRevisions < ActiveRecord::Migration[6.1]
def change
add_reference :procedure_revisions, :attestation_template, foreign_key: { to_table: :attestation_templates }, null: true, index: true
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_12_02_133139) do ActiveRecord::Schema.define(version: 2022_01_10_133139) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -593,6 +593,8 @@ ActiveRecord::Schema.define(version: 2021_12_02_133139) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.datetime "published_at" t.datetime "published_at"
t.bigint "attestation_template_id"
t.index ["attestation_template_id"], name: "index_procedure_revisions_on_attestation_template_id"
t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id" t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id"
end end
@ -872,6 +874,7 @@ ActiveRecord::Schema.define(version: 2021_12_02_133139) do
add_foreign_key "procedure_revision_types_de_champ", "procedure_revision_types_de_champ", column: "parent_id" add_foreign_key "procedure_revision_types_de_champ", "procedure_revision_types_de_champ", column: "parent_id"
add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id" add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id"
add_foreign_key "procedure_revision_types_de_champ", "types_de_champ" add_foreign_key "procedure_revision_types_de_champ", "types_de_champ"
add_foreign_key "procedure_revisions", "attestation_templates"
add_foreign_key "procedure_revisions", "procedures" add_foreign_key "procedure_revisions", "procedures"
add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id" add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id"
add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id" add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id"

View file

@ -1,8 +1,8 @@
include ActionDispatch::TestProcess include ActionDispatch::TestProcess
describe Administrateurs::AttestationTemplatesController, type: :controller do describe Administrateurs::AttestationTemplatesController, type: :controller do
let!(:attestation_template) { create(:attestation_template) }
let(:admin) { create(:administrateur) } let(:admin) { create(:administrateur) }
let(:attestation_template) { build(:attestation_template) }
let!(:procedure) { create :procedure, administrateur: admin, attestation_template: attestation_template } let!(:procedure) { create :procedure, administrateur: admin, attestation_template: attestation_template }
let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') } let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
let(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') } let(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
@ -41,7 +41,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
end end
context 'if an attestation template exists on the procedure' do context 'if an attestation template exists on the procedure' do
after { procedure.attestation_template.destroy } after { procedure.draft_revision.attestation_template&.destroy }
context 'with images' do context 'with images' do
let!(:attestation_template) do let!(:attestation_template) do
@ -115,14 +115,14 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
procedure.reload procedure.reload
end end
it { expect(procedure.attestation_template).to have_attributes(attestation_params) } it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
it { expect(procedure.attestation_template.activated).to be true } it { expect(procedure.draft_attestation_template.activated).to be true }
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) } it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) } it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) } it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
it { expect(flash.notice).to eq("L'attestation a bien été sauvegardée") } it { expect(flash.notice).to eq("L'attestation a bien été sauvegardée") }
after { procedure.attestation_template.destroy } after { procedure.draft_attestation_template.destroy }
end end
context 'when something wrong happens in the attestation template creation' do context 'when something wrong happens in the attestation template creation' do
@ -140,7 +140,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) } it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
it { expect(flash.alert).to be_present } it { expect(flash.alert).to be_present }
it { expect(procedure.attestation_template).to be nil } it { expect(procedure.draft_attestation_template).to be nil }
end end
end end
@ -158,13 +158,13 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
procedure.reload procedure.reload
end end
it { expect(procedure.attestation_template).to have_attributes(attestation_params) } it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) } it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) } it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) } it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
it { expect(flash.notice).to eq("L'attestation a bien été modifiée") } it { expect(flash.notice).to eq("L'attestation a bien été modifiée") }
after { procedure.attestation_template.destroy } after { procedure.draft_attestation_template&.destroy }
end end
context 'when something wrong happens in the attestation template creation' do context 'when something wrong happens in the attestation template creation' do

View file

@ -4,8 +4,6 @@ FactoryBot.define do
body { 'body' } body { 'body' }
footer { 'footer' } footer { 'footer' }
activated { true } activated { true }
association :procedure
end end
trait :with_files do trait :with_files do

View file

@ -23,10 +23,11 @@ FactoryBot.define do
types_de_champ { [] } types_de_champ { [] }
types_de_champ_private { [] } types_de_champ_private { [] }
updated_at { nil } updated_at { nil }
attestation_template { }
end end
after(:build) do |procedure, evaluator| after(:build) do |procedure, evaluator|
initial_revision = build(:procedure_revision, procedure: procedure) initial_revision = build(:procedure_revision, procedure: procedure, attestation_template: evaluator.attestation_template)
add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public) add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public)
add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private) add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private)

View file

@ -66,16 +66,12 @@ describe Procedure do
end end
describe '#closed_mail_template_attestation_inconsistency_state' do describe '#closed_mail_template_attestation_inconsistency_state' do
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail) } let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail, attestation_template: nil) }
let(:procedure_with_active_attestation) do let(:procedure_with_active_attestation) do
procedure = create(:procedure, closed_mail: closed_mail) create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: true))
create(:attestation_template, procedure: procedure, activated: true)
procedure
end end
let(:procedure_with_inactive_attestation) do let(:procedure_with_inactive_attestation) do
procedure = create(:procedure, closed_mail: closed_mail) create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: false))
create(:attestation_template, procedure: procedure, activated: false)
procedure
end end
subject { procedure.closed_mail_template_attestation_inconsistency_state } subject { procedure.closed_mail_template_attestation_inconsistency_state }

View file

@ -1,5 +1,6 @@
describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml', type: :view do describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml', type: :view do
let(:procedure) { create(:procedure, closed_mail: closed_mail) } let(:procedure) { create(:procedure, closed_mail: closed_mail, attestation_template: attestation_template) }
let(:attestation_template) { nil }
def alert def alert
assign(:procedure, procedure) assign(:procedure, procedure)
@ -23,7 +24,7 @@ describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml'
context 'when there is an active attestation but the closed mail template does not mention it' do context 'when there is an active attestation but the closed mail template does not mention it' do
let(:closed_mail) { create(:closed_mail) } let(:closed_mail) { create(:closed_mail) }
let!(:attestation_template) { create(:attestation_template, procedure: procedure, activated: true) } let(:attestation_template) { build(:attestation_template) }
it { expect(alert).to include("Cette démarche comporte une attestation, mais laccusé dacceptation ne la mentionne pas") } it { expect(alert).to include("Cette démarche comporte une attestation, mais laccusé dacceptation ne la mentionne pas") }
it { expect(alert).to include(edit_admin_procedure_mail_template_path(procedure, Mails::ClosedMail::SLUG)) } it { expect(alert).to include(edit_admin_procedure_mail_template_path(procedure, Mails::ClosedMail::SLUG)) }