diff --git a/app/controllers/administrateurs/attestation_templates_controller.rb b/app/controllers/administrateurs/attestation_templates_controller.rb index aff0bb793..d1f66ebad 100644 --- a/app/controllers/administrateurs/attestation_templates_controller.rb +++ b/app/controllers/administrateurs/attestation_templates_controller.rb @@ -3,12 +3,17 @@ module Administrateurs before_action :retrieve_procedure def edit - @attestation_template = @procedure.attestation_template || AttestationTemplate.new(procedure: @procedure) + @attestation_template = build_attestation end def update - attestation_template = @procedure.attestation_template + attestation_template = @procedure.draft_attestation_template.revise! + 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" else flash.alert = attestation_template.errors.full_messages.join('
') @@ -18,7 +23,7 @@ module Administrateurs end 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 flash.notice = "L'attestation a bien été sauvegardée" @@ -30,14 +35,19 @@ module Administrateurs end def preview - attestation = @procedure.attestation_template || AttestationTemplate.new - @attestation = attestation.render_attributes_for({}) + @attestation = build_attestation.render_attributes_for({}) render 'administrateurs/attestation_templates/show', formats: [:pdf] end 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 # cache result to avoid multiple uninterlaced computations if @activated_attestation_params.nil? diff --git a/app/models/attestation_template.rb b/app/models/attestation_template.rb index 6062589e8..deab7b0a2 100644 --- a/app/models/attestation_template.rb +++ b/app/models/attestation_template.rb @@ -15,7 +15,8 @@ class AttestationTemplate < ApplicationRecord include ActionView::Helpers::NumberHelper 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 :signature @@ -103,6 +104,25 @@ class AttestationTemplate < ApplicationRecord } 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 def used_tags diff --git a/app/models/dossier.rb b/app/models/dossier.rb index c0f11c577..83a91032a 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -720,9 +720,11 @@ class Dossier < ApplicationRecord { lon: lon, lat: lat, zoom: zoom } end - def unspecified_attestation_champs - attestation_template = procedure.attestation_template + def attestation_template + revision.attestation_template + end + def unspecified_attestation_champs if attestation_template&.activated? attestation_template.unspecified_champs_for_dossier(self) else @@ -731,8 +733,8 @@ class Dossier < ApplicationRecord end def build_attestation - if procedure.attestation_template&.activated? - procedure.attestation_template.attestation_for(self) + if attestation_template&.activated? + attestation_template.attestation_for(self) end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index dec7d8a27..f3894815c 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -77,12 +77,15 @@ class Procedure < ApplicationRecord 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_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, through: :experts_procedures has_one :module_api_carto, 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 :canonical_procedure, class_name: 'Procedure', optional: true @@ -438,7 +441,8 @@ class Procedure < ApplicationRecord }, revision_types_de_champ_private: { type_de_champ: :types_de_champ - } + }, + attestation_template: [] } } include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin @@ -576,13 +580,17 @@ class Procedure < ApplicationRecord touch(:whitelisted_at) end + def active_attestation_template + published_attestation_template || draft_attestation_template + end + def closed_mail_template_attestation_inconsistency_state # As an optimization, don’t check the predefined templates (they are presumed correct) if closed_mail.present? 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 - elsif !attestation_template&.activated? && tag_present + elsif !active_attestation_template&.activated? && tag_present :extraneous_tag end end diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index 7c0a19c48..da60bb296 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -2,15 +2,17 @@ # # Table name: procedure_revisions # -# id :bigint not null, primary key -# published_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# procedure_id :bigint not null +# id :bigint not null, primary key +# published_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# attestation_template_id :bigint +# procedure_id :bigint not null # class ProcedureRevision < ApplicationRecord self.implicit_order_column = :created_at 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 @@ -125,6 +127,10 @@ class ProcedureRevision < ApplicationRecord ) end + def attestation_template + super || procedure.attestation_template + end + private def compare_types_de_champ(from_tdc, to_tdc) diff --git a/app/views/administrateurs/procedures/show.html.haml b/app/views/administrateurs/procedures/show.html.haml index c0985cf4e..04dc0bb42 100644 --- a/app/views/administrateurs/procedures/show.html.haml +++ b/app/views/administrateurs/procedures/show.html.haml @@ -138,7 +138,7 @@ .procedure-grid = 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 %span.icon.accept %p.card-admin-status-accept Activée diff --git a/db/migrate/20211214145059_add_attestation_template_id_to_procedure_revisions.rb b/db/migrate/20211214145059_add_attestation_template_id_to_procedure_revisions.rb new file mode 100644 index 000000000..b0ffc5b82 --- /dev/null +++ b/db/migrate/20211214145059_add_attestation_template_id_to_procedure_revisions.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 973f86d48..31cc440d2 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: 2022_01_27_135056) do +ActiveRecord::Schema.define(version: 2022_01_28_135056) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -593,6 +593,8 @@ ActiveRecord::Schema.define(version: 2022_01_27_135056) do t.datetime "created_at", null: false t.datetime "updated_at", null: false 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" end @@ -872,6 +874,7 @@ ActiveRecord::Schema.define(version: 2022_01_27_135056) 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_revisions", column: "revision_id" 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 "procedures", "procedure_revisions", column: "draft_revision_id" add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id" diff --git a/lib/tasks/deployment/20220112184331_revise_attestation_templates.rake b/lib/tasks/deployment/20220112184331_revise_attestation_templates.rake index 9478bb490..24116586c 100644 --- a/lib/tasks/deployment/20220112184331_revise_attestation_templates.rake +++ b/lib/tasks/deployment/20220112184331_revise_attestation_templates.rake @@ -3,14 +3,16 @@ namespace :after_party do task revise_attestation_templates: :environment do rake_puts "Running deploy task 'revise_attestation_templates'" - attestation_templates = AttestationTemplate.where.not(procedure_id: nil) - progress = ProgressReport.new(attestation_templates.count) + revisions = ProcedureRevision + .joins(procedure: :attestation_template) + .where(attestation_template_id: nil) + + progress = ProgressReport.new(revisions.count) + + revisions.find_each do |revision| + attestation_template_id = revision.procedure.attestation_template.id + revision.update_column(:attestation_template_id, attestation_template_id) - attestation_templates.find_each do |attestation_template| - ProcedureRevision - .where(procedure_id: attestation_template.procedure_id, attestation_template_id: nil) - .update_all(attestation_template_id: attestation_template) - attestation_template.update_column(:procedure_id, nil) progress.inc end progress.finish diff --git a/spec/controllers/administrateurs/attestation_templates_controller_spec.rb b/spec/controllers/administrateurs/attestation_templates_controller_spec.rb index 401eb0be1..451bd30f0 100644 --- a/spec/controllers/administrateurs/attestation_templates_controller_spec.rb +++ b/spec/controllers/administrateurs/attestation_templates_controller_spec.rb @@ -1,8 +1,8 @@ include ActionDispatch::TestProcess describe Administrateurs::AttestationTemplatesController, type: :controller do - let!(:attestation_template) { create(:attestation_template) } let(:admin) { create(:administrateur) } + let(:attestation_template) { build(: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(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') } @@ -41,7 +41,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do end 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 let!(:attestation_template) do @@ -115,14 +115,14 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do procedure.reload end - it { expect(procedure.attestation_template).to have_attributes(attestation_params) } - it { expect(procedure.attestation_template.activated).to be true } - it { expect(procedure.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).to have_attributes(attestation_params) } + it { expect(procedure.draft_attestation_template.activated).to be true } + it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.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(flash.notice).to eq("L'attestation a bien été sauvegardée") } - after { procedure.attestation_template.destroy } + after { procedure.draft_attestation_template.destroy } end 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(flash.alert).to be_present } - it { expect(procedure.attestation_template).to be nil } + it { expect(procedure.draft_attestation_template).to be nil } end end @@ -158,13 +158,13 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do procedure.reload end - it { expect(procedure.attestation_template).to have_attributes(attestation_params) } - it { expect(procedure.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).to have_attributes(attestation_params) } + it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.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(flash.notice).to eq("L'attestation a bien été modifiée") } - after { procedure.attestation_template.destroy } + after { procedure.draft_attestation_template&.destroy } end context 'when something wrong happens in the attestation template creation' do diff --git a/spec/factories/attestation_template.rb b/spec/factories/attestation_template.rb index eb3e98727..6e6110363 100644 --- a/spec/factories/attestation_template.rb +++ b/spec/factories/attestation_template.rb @@ -4,8 +4,6 @@ FactoryBot.define do body { 'body' } footer { 'footer' } activated { true } - - association :procedure end trait :with_files do diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index ec7a25b67..a99eb46f3 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -23,10 +23,11 @@ FactoryBot.define do types_de_champ { [] } types_de_champ_private { [] } updated_at { nil } + attestation_template { nil } end 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_private, to: initial_revision, scope: :private) diff --git a/spec/lib/tasks/deployment/20220112184331_revise_attestation_templates_spec.rb b/spec/lib/tasks/deployment/20220112184331_revise_attestation_templates_spec.rb new file mode 100644 index 000000000..5abc757d3 --- /dev/null +++ b/spec/lib/tasks/deployment/20220112184331_revise_attestation_templates_spec.rb @@ -0,0 +1,22 @@ +describe '20220112184331_revise_attestation_templates' do + let(:rake_task) { Rake::Task['after_party:revise_attestation_templates'] } + let(:procedure) { create(:procedure) } + let(:attestation_template) { create(:attestation_template, procedure: procedure) } + + subject(:run_task) do + attestation_template + rake_task.invoke + attestation_template.reload + end + + after { rake_task.reenable } + + describe 'revise_attestation_templates' do + it 'attaches the attestation_template to the latest revision (without removing the link between attestation_template and procedure for now)' do + expect(attestation_template.procedure.revisions.first.attestation_template_id).to be_nil + run_task + expect(attestation_template.procedure_id).to eq(procedure.id) + expect(attestation_template.procedure.revisions.first.attestation_template_id).to eq(attestation_template.id) + end + end +end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 82ff19c73..4602aa7dd 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -66,16 +66,12 @@ describe Procedure do end 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 - procedure = create(:procedure, closed_mail: closed_mail) - create(:attestation_template, procedure: procedure, activated: true) - procedure + create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: true)) end let(:procedure_with_inactive_attestation) do - procedure = create(:procedure, closed_mail: closed_mail) - create(:attestation_template, procedure: procedure, activated: false) - procedure + create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: false)) end subject { procedure.closed_mail_template_attestation_inconsistency_state } diff --git a/spec/views/administrateurs/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec.rb b/spec/views/administrateurs/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec.rb index 642952738..d4c49f6c2 100644 --- a/spec/views/administrateurs/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec.rb +++ b/spec/views/administrateurs/_closed_mail_template_attestation_inconsistency_alert.html.haml_spec.rb @@ -1,5 +1,6 @@ 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 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 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 l’accusé d’acceptation ne la mentionne pas") } it { expect(alert).to include(edit_admin_procedure_mail_template_path(procedure, Mails::ClosedMail::SLUG)) }