From 219eaf0d5e1bbb39ba256e7a14d32930ce674525 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 1 Dec 2021 20:00:29 +0100 Subject: [PATCH 01/19] add zone model --- app/models/zone.rb | 13 +++++++++++++ db/migrate/20211127133549_create_zones.rb | 10 ++++++++++ db/schema.rb | 9 ++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 app/models/zone.rb create mode 100644 db/migrate/20211127133549_create_zones.rb diff --git a/app/models/zone.rb b/app/models/zone.rb new file mode 100644 index 000000000..31383ffc5 --- /dev/null +++ b/app/models/zone.rb @@ -0,0 +1,13 @@ +# == Schema Information +# +# Table name: zones +# +# id :bigint not null, primary key +# acronym :string +# label :string +# created_at :datetime not null +# updated_at :datetime not null +# +class Zone < ApplicationRecord + validates :acronym, presence: true, uniqueness: true +end diff --git a/db/migrate/20211127133549_create_zones.rb b/db/migrate/20211127133549_create_zones.rb new file mode 100644 index 000000000..d98b30b2d --- /dev/null +++ b/db/migrate/20211127133549_create_zones.rb @@ -0,0 +1,10 @@ +class CreateZones < ActiveRecord::Migration[6.1] + def change + create_table :zones do |t| + t.string :acronym + t.string :label + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9d45dd8de..6cd7e79c8 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_11_26_150915) do +ActiveRecord::Schema.define(version: 2021_11_27_133549) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -823,6 +823,13 @@ ActiveRecord::Schema.define(version: 2021_11_26_150915) do t.index ["procedure_id"], name: "index_without_continuation_mails_on_procedure_id" end + create_table "zones", force: :cascade do |t| + t.string "acronym" + t.string "label" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "archives_groupe_instructeurs", "archives" add_foreign_key "archives_groupe_instructeurs", "groupe_instructeurs" From 5b8d872b6e640e50df2b84336831be60d537230a Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 1 Dec 2021 20:34:55 +0100 Subject: [PATCH 02/19] populate zones --- config/zones.yml | 37 +++++++++++++++++++ .../20211116140232_populate_zones.rake | 17 +++++++++ .../20211116140232_populate_zones_spec.rb | 11 ++++++ 3 files changed, 65 insertions(+) create mode 100644 config/zones.yml create mode 100644 lib/tasks/deployment/20211116140232_populate_zones.rake create mode 100644 spec/lib/tasks/deployment/20211116140232_populate_zones_spec.rb diff --git a/config/zones.yml b/config/zones.yml new file mode 100644 index 000000000..32c32c2d1 --- /dev/null +++ b/config/zones.yml @@ -0,0 +1,37 @@ +ministeres: + - MAA: + label: "Ministère de l'Agriculture et de l'Alimentation" + - MC: + label: "Ministère de la Culture" + - MAS: + label: "Ministère des Solidarités et de la Santé" + - MTEI: + label: "Ministère du Travail" + - MEAE: + label: "Ministère de l'Europe et des Affaires étrangères" + - MEF: + label: "Ministère de l'Économie, des Finances et de la Relance" + - MJS: + label: "Ministère de la Jeunesse et des Sports" + - EN: + label: "Ministère de l'Éducation nationale, de la Jeunesse et des Sports" + - ESR: + label: "Ministère de l'Enseignement supérieur, de la Recherche et de l'Innovation" + - MI: + label: "Ministère de l'Intérieur" + - MInArm: + label: "Ministère des Armées" + - MJ: + label: "Ministère de la Justice" + - MTES: + label: "Ministère de la Transition écologique" + - MCTRCT: + label: "Ministère de la Cohésion des territoires et des Relations avec les collectivités territoriales" + - SPM: + label: "Premier ministre" + - MER: + label: "Ministère de la Mer" + - MTFP: + label: "Ministère de la Transformation et de la Fonction publiques" + - OM: + label: "Ministère des Outre-mer" diff --git a/lib/tasks/deployment/20211116140232_populate_zones.rake b/lib/tasks/deployment/20211116140232_populate_zones.rake new file mode 100644 index 000000000..4d97f86a5 --- /dev/null +++ b/lib/tasks/deployment/20211116140232_populate_zones.rake @@ -0,0 +1,17 @@ +namespace :after_party do + desc 'Deployment task: populate_zones' + task populate_zones: :environment do + puts "Running deploy task 'populate_zones'" + + Zone.create!(acronym: 'COLLECTIVITE', label: 'Collectivité territoriale') + config = Psych.safe_load(File.read(Rails.root.join("config", "zones.yml"))) + config["ministeres"].each do |ministere| + acronym = ministere.keys.first + Zone.create!(acronym: acronym, label: ministere["label"]) + 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/lib/tasks/deployment/20211116140232_populate_zones_spec.rb b/spec/lib/tasks/deployment/20211116140232_populate_zones_spec.rb new file mode 100644 index 000000000..9018fb96f --- /dev/null +++ b/spec/lib/tasks/deployment/20211116140232_populate_zones_spec.rb @@ -0,0 +1,11 @@ +describe '20211116140232_populate_zones' do + let(:rake_task) { Rake::Task['after_party:populate_zones'] } + subject(:run_task) do + rake_task.invoke + end + + it 'populates zones' do + run_task + expect(Zone.find_by(acronym: 'SPM').label).to eq "Premier ministre" + end +end From 561f6fb274f1dcf7f70e63afd1551a36546ef7af Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 1 Dec 2021 21:05:15 +0100 Subject: [PATCH 03/19] add belongs_to zone for procedure --- app/models/procedure.rb | 2 ++ db/migrate/20211127143736_add_zone_to_procedures.rb | 5 +++++ db/schema.rb | 5 ++++- spec/factories/procedure.rb | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20211127143736_add_zone_to_procedures.rb diff --git a/app/models/procedure.rb b/app/models/procedure.rb index e85548ce1..eab2c373d 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -48,6 +48,7 @@ # parent_procedure_id :bigint # published_revision_id :bigint # service_id :bigint +# zone_id :bigint # class Procedure < ApplicationRecord @@ -85,6 +86,7 @@ class Procedure < ApplicationRecord belongs_to :parent_procedure, class_name: 'Procedure', optional: true belongs_to :canonical_procedure, class_name: 'Procedure', optional: true belongs_to :service, optional: true + belongs_to :zone, optional: true def active_revision brouillon? ? draft_revision : published_revision diff --git a/db/migrate/20211127143736_add_zone_to_procedures.rb b/db/migrate/20211127143736_add_zone_to_procedures.rb new file mode 100644 index 000000000..4fa95f3f8 --- /dev/null +++ b/db/migrate/20211127143736_add_zone_to_procedures.rb @@ -0,0 +1,5 @@ +class AddZoneToProcedures < ActiveRecord::Migration[6.1] + def change + add_reference :procedures, :zone, null: true, foreign_key: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 6cd7e79c8..6c8fad2c6 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_11_27_133549) do +ActiveRecord::Schema.define(version: 2021_11_27_143736) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -638,6 +638,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_133549) do t.text "api_particulier_scopes", default: [], array: true t.jsonb "api_particulier_sources", default: {} t.boolean "instructeurs_self_management_enabled" + t.bigint "zone_id" t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin t.boolean "routing_enabled" t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state" @@ -648,6 +649,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_133549) do t.index ["path", "closed_at", "hidden_at"], name: "index_procedures_on_path_and_closed_at_and_hidden_at", unique: true t.index ["published_revision_id"], name: "index_procedures_on_published_revision_id" t.index ["service_id"], name: "index_procedures_on_service_id" + t.index ["zone_id"], name: "index_procedures_on_zone_id" end create_table "received_mails", id: :serial, force: :cascade do |t| @@ -865,6 +867,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_133549) do add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id" add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id" add_foreign_key "procedures", "services" + add_foreign_key "procedures", "zones" add_foreign_key "received_mails", "procedures" add_foreign_key "refused_mails", "procedures" add_foreign_key "services", "administrateurs" diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index 1b6a622d2..8d8cc7fa9 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -12,6 +12,7 @@ FactoryBot.define do ask_birthday { false } lien_site_web { "https://mon-site.gouv" } path { SecureRandom.uuid } + association :zone groupe_instructeurs { [association(:groupe_instructeur, :default, procedure: instance, strategy: :build)] } administrateurs { administrateur.present? ? [administrateur] : [association(:administrateur)] } From 9341c787a1f5a6ed0128ebf96fe74ed6faf30ae6 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 1 Dec 2021 21:38:41 +0100 Subject: [PATCH 04/19] administrateur can add zone to procedure --- app/controllers/administrateurs/procedures_controller.rb | 2 +- .../administrateurs/procedures/_informations.html.haml | 5 +++++ .../administrateurs/procedures_controller_spec.rb | 2 ++ spec/factories/zone.rb | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 spec/factories/zone.rb diff --git a/app/controllers/administrateurs/procedures_controller.rb b/app/controllers/administrateurs/procedures_controller.rb index f01c15556..08f39c5ec 100644 --- a/app/controllers/administrateurs/procedures_controller.rb +++ b/app/controllers/administrateurs/procedures_controller.rb @@ -251,7 +251,7 @@ module Administrateurs end def procedure_params - editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :declarative_with_state, :logo, :auto_archive_on, :monavis_embed, :api_entreprise_token, :duree_conservation_dossiers_dans_ds] + editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :declarative_with_state, :logo, :auto_archive_on, :monavis_embed, :api_entreprise_token, :duree_conservation_dossiers_dans_ds, :zone_id] permited_params = if @procedure&.locked? params.require(:procedure).permit(*editable_params) else diff --git a/app/views/administrateurs/procedures/_informations.html.haml b/app/views/administrateurs/procedures/_informations.html.haml index d48d963cd..7cc1a1ec5 100644 --- a/app/views/administrateurs/procedures/_informations.html.haml +++ b/app/views/administrateurs/procedures/_informations.html.haml @@ -13,6 +13,11 @@ %span.mandatory * = f.text_area :description, rows: '6', placeholder: 'Description de la démarche, destinataires, etc. ', class: 'form-control' += f.label :zone do + Organisme qui met en oeuvre la démarche + %span.mandatory * += f.collection_select :zone_id, Zone.order(:label), :id, :label, prompt: true + %h3.header-subsection Logo de la démarche = image_upload_and_render f, @procedure.logo diff --git a/spec/controllers/administrateurs/procedures_controller_spec.rb b/spec/controllers/administrateurs/procedures_controller_spec.rb index ce5f5f0f6..378910d35 100644 --- a/spec/controllers/administrateurs/procedures_controller_spec.rb +++ b/spec/controllers/administrateurs/procedures_controller_spec.rb @@ -7,6 +7,7 @@ describe Administrateurs::ProceduresController, type: :controller do let(:description) { 'Description de test' } let(:organisation) { 'Organisation de test' } let(:direction) { 'Direction de test' } + let(:ministere) { create(:zone) } let(:cadre_juridique) { 'cadre juridique' } let(:duree_conservation_dossiers_dans_ds) { 3 } let(:monavis_embed) { nil } @@ -30,6 +31,7 @@ describe Administrateurs::ProceduresController, type: :controller do description: description, organisation: organisation, direction: direction, + ministere: ministere, cadre_juridique: cadre_juridique, duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds, monavis_embed: monavis_embed, diff --git a/spec/factories/zone.rb b/spec/factories/zone.rb new file mode 100644 index 000000000..63fb8b925 --- /dev/null +++ b/spec/factories/zone.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :zone do + sequence(:acronym) { |n| "MA#{n}" } + sequence(:label) { |n| "Ministère de l'Education Populaire #{n}" } + end +end From b2902340aff99164e123b8e7ea033fa621665b1c Mon Sep 17 00:00:00 2001 From: krichtof Date: Wed, 24 Nov 2021 06:09:51 +0100 Subject: [PATCH 05/19] add db constraints for ministere Co-authored-by: Paul Chavard --- db/migrate/20211127133549_create_zones.rb | 2 +- db/schema.rb | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/db/migrate/20211127133549_create_zones.rb b/db/migrate/20211127133549_create_zones.rb index d98b30b2d..f3a54c108 100644 --- a/db/migrate/20211127133549_create_zones.rb +++ b/db/migrate/20211127133549_create_zones.rb @@ -1,7 +1,7 @@ class CreateZones < ActiveRecord::Migration[6.1] def change create_table :zones do |t| - t.string :acronym + t.string :acronym, null: false, index: { unique: true } t.string :label t.timestamps diff --git a/db/schema.rb b/db/schema.rb index 6c8fad2c6..64a46604c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -554,6 +554,14 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.index ["user_id"], name: "index_merge_logs_on_user_id" end + create_table "zones", force: :cascade do |t| + t.string "acronym", null: false + t.string "label" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["acronym"], name: "index_zones_on_acronym", unique: true + end + create_table "module_api_cartos", id: :serial, force: :cascade do |t| t.integer "procedure_id" t.boolean "use_api_carto", default: false @@ -825,13 +833,6 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.index ["procedure_id"], name: "index_without_continuation_mails_on_procedure_id" end - create_table "zones", force: :cascade do |t| - t.string "acronym" - t.string "label" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - end - add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "archives_groupe_instructeurs", "archives" add_foreign_key "archives_groupe_instructeurs", "groupe_instructeurs" From 3265ac2d8465cd3a21db88f95fa3720ce0c82b1e Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 2 Dec 2021 16:04:05 +0100 Subject: [PATCH 06/19] localize zone --- app/views/administrateurs/procedures/_informations.html.haml | 2 +- config/locales/fr.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/administrateurs/procedures/_informations.html.haml b/app/views/administrateurs/procedures/_informations.html.haml index 7cc1a1ec5..b821023d5 100644 --- a/app/views/administrateurs/procedures/_informations.html.haml +++ b/app/views/administrateurs/procedures/_informations.html.haml @@ -14,7 +14,7 @@ = f.text_area :description, rows: '6', placeholder: 'Description de la démarche, destinataires, etc. ', class: 'form-control' = f.label :zone do - Organisme qui met en oeuvre la démarche + = t('zone', scope: 'activerecord.attributes.procedure') %span.mandatory * = f.collection_select :zone_id, Zone.order(:label), :id, :label, prompt: true diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b44788763..a46c36683 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -248,6 +248,8 @@ fr: << : *default_attributes super_admin: << : *default_attributes + procedure: + zone: Organisme qui met en œuvre la démarche errors: messages: not_a_phone: 'Numéro de téléphone invalide' From f8a17b2cc4a01d259bbaae29fce1fa54789be8b6 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 26 Nov 2021 16:10:03 +0100 Subject: [PATCH 07/19] feat(procedures#index): add dossiers-expirant to instructeur/procedure#index --- app/controllers/instructeurs/procedures_controller.rb | 7 ++++--- app/views/instructeurs/procedures/_list.html.haml | 8 ++++++++ app/views/instructeurs/procedures/index.html.haml | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index e72caa804..dda4c0394 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -15,9 +15,9 @@ module Instructeurs dossiers = current_instructeur.dossiers.joins(:groupe_instructeur) @dossiers_count_per_procedure = dossiers.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count - @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count + @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) @dossiers_termines_count_per_procedure = dossiers.termine.group('groupe_instructeurs.procedure_id').reorder(nil).count - + @dossiers_expirant_count_per_procedure = dossiers.close_to_expiration.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) groupe_ids = current_instructeur.groupe_instructeurs.pluck(:id) @followed_dossiers_count_per_procedure = current_instructeur @@ -34,7 +34,8 @@ module Instructeurs 'suivis' => @followed_dossiers_count_per_procedure.sum { |_, v| v }, 'traités' => @dossiers_termines_count_per_procedure.sum { |_, v| v }, 'dossiers' => @dossiers_count_per_procedure.sum { |_, v| v }, - 'archivés' => @dossiers_archived_count_per_procedure.sum { |_, v| v } + 'archivés' => @dossiers_archived_count_per_procedure.sum { |_, v| v }, + 'expirant' => @dossiers_expirant_count_per_procedure.sum { |_, v| v } } @procedure_ids_en_cours_with_notifications = current_instructeur.procedure_ids_with_notifications(:en_cours) diff --git a/app/views/instructeurs/procedures/_list.html.haml b/app/views/instructeurs/procedures/_list.html.haml index a0b1ca2a5..96c25d2b2 100644 --- a/app/views/instructeurs/procedures/_list.html.haml +++ b/app/views/instructeurs/procedures/_list.html.haml @@ -52,6 +52,14 @@ = number_with_html_delimiter(archived_count) .stats-legend = t('pluralize.archived', count: archived_count) + %li + %object + = link_to(instructeur_procedure_path(p, statut: 'expirant')) do + - expirant_count = dossiers_expirant_count_per_procedure[p.id] || 0 + .stats-number + = number_with_html_delimiter(expirant_count) + .stats-legend + = t('pluralize.dossiers_close_to_expiration', count: expirant_count) - if p.close? .procedure-status diff --git a/app/views/instructeurs/procedures/index.html.haml b/app/views/instructeurs/procedures/index.html.haml index 3616a7090..4356c463e 100644 --- a/app/views/instructeurs/procedures/index.html.haml +++ b/app/views/instructeurs/procedures/index.html.haml @@ -12,6 +12,7 @@ dossiers_a_suivre_count_per_procedure: @dossiers_a_suivre_count_per_procedure, dossiers_archived_count_per_procedure: @dossiers_archived_count_per_procedure, dossiers_termines_count_per_procedure: @dossiers_termines_count_per_procedure, + dossiers_expirant_count_per_procedure: @dossiers_expirant_count_per_procedure, followed_dossiers_count_per_procedure: @followed_dossiers_count_per_procedure, procedure_ids_en_cours_with_notifications: @procedure_ids_en_cours_with_notifications, procedure_ids_termines_with_notifications: @procedure_ids_termines_with_notifications } From ce87878ff0a0303ee08000b331077b1849d0491c Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 30 Nov 2021 14:47:19 +0100 Subject: [PATCH 08/19] refactor(traitement.process_expired): move process expired to procedure --- app/models/dossier.rb | 24 +++++------- app/models/procedure.rb | 1 + app/models/traitement.rb | 15 ++++---- ...52402_move_process_expire_to_procedures.rb | 17 +++++++++ db/schema.rb | 11 +++++- ...aitement_process_expired_to_procedure.rake | 21 +++++++++++ spec/models/dossier_spec.rb | 37 +++---------------- 7 files changed, 70 insertions(+), 56 deletions(-) create mode 100644 db/migrate/20211126152402_move_process_expire_to_procedures.rb create mode 100644 lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 08d12bf3d..1e41ffe4e 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -24,6 +24,7 @@ # last_commentaire_updated_at :datetime # motivation :text # private_search_terms :text +# process_expired :boolean default(FALSE) # processed_at :datetime # search_terms :text # state :string @@ -91,20 +92,17 @@ class Dossier < ApplicationRecord def passer_en_construction(instructeur: nil, processed_at: Time.zone.now) build(state: Dossier.states.fetch(:en_construction), instructeur_email: instructeur&.email, - process_expired: false, processed_at: processed_at) end def passer_en_instruction(instructeur: nil, processed_at: Time.zone.now) build(state: Dossier.states.fetch(:en_instruction), instructeur_email: instructeur&.email, - process_expired: false, processed_at: processed_at) end def accepter_automatiquement(processed_at: Time.zone.now) build(state: Dossier.states.fetch(:accepte), - process_expired: proxy_association.owner.procedure.feature_enabled?(:procedure_process_expired_dossiers_termine), processed_at: processed_at) end @@ -112,7 +110,6 @@ class Dossier < ApplicationRecord build(state: Dossier.states.fetch(:accepte), instructeur_email: instructeur&.email, motivation: motivation, - process_expired: proxy_association.owner.procedure.feature_enabled?(:procedure_process_expired_dossiers_termine), processed_at: processed_at) end @@ -120,7 +117,6 @@ class Dossier < ApplicationRecord build(state: Dossier.states.fetch(:refuse), instructeur_email: instructeur&.email, motivation: motivation, - process_expired: proxy_association.owner.procedure.feature_enabled?(:procedure_process_expired_dossiers_termine), processed_at: processed_at) end @@ -128,7 +124,6 @@ class Dossier < ApplicationRecord build(state: Dossier.states.fetch(:sans_suite), instructeur_email: instructeur&.email, motivation: motivation, - process_expired: proxy_association.owner.procedure.feature_enabled?(:procedure_process_expired_dossiers_termine), processed_at: processed_at) end end @@ -300,11 +295,10 @@ class Dossier < ApplicationRecord scope :interval_en_construction_close_to_expiration, -> do state_en_construction.where("dossiers.en_construction_at + dossiers.conservation_extension + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION }) end - scope :interval_en_instruction_close_to_expiration, -> do - state_en_instruction.where("dossiers.en_instruction_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION }) - end scope :interval_termine_close_to_expiration, -> do - state_termine.where(id: Traitement.termine_close_to_expiration.select(:dossier_id).distinct) + state_termine + .where(procedures: { procedure_expires_when_termine_enabled: true}) + .where("dossiers.processed_at + dossiers.conservation_extension + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION }) end scope :brouillon_close_to_expiration, -> do @@ -313,9 +307,6 @@ class Dossier < ApplicationRecord scope :en_construction_close_to_expiration, -> do joins(:procedure).interval_en_construction_close_to_expiration end - scope :en_instruction_close_to_expiration, -> do - joins(:procedure).interval_en_instruction_close_to_expiration - end scope :termine_close_to_expiration, -> do joins(:procedure).interval_termine_close_to_expiration end @@ -324,7 +315,6 @@ class Dossier < ApplicationRecord joins(:procedure).scoping do interval_brouillon_close_to_expiration .or(interval_en_construction_close_to_expiration) - .or(interval_en_instruction_close_to_expiration) .or(interval_termine_close_to_expiration) end end @@ -545,7 +535,11 @@ class Dossier < ApplicationRecord end def expirable? - [brouillon?, en_construction?, termine? && procedure.feature_enabled?(:procedure_process_expired_dossiers_termine)].any? + [ + brouillon?, + en_construction?, + termine? && procedure.procedure_expires_when_termine_enabled + ].any? end def approximative_expiration_date_reference diff --git a/app/models/procedure.rb b/app/models/procedure.rb index eab2c373d..7d4397392 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -34,6 +34,7 @@ # monavis_embed :text # organisation :string # path :string not null +# procedure_expires_when_termine_enabled :boolean default(FALSE) # published_at :datetime # routing_criteria_name :text default("Votre ville") # routing_enabled :boolean diff --git a/app/models/traitement.rb b/app/models/traitement.rb index 8e6ce610f..86d7fd79b 100644 --- a/app/models/traitement.rb +++ b/app/models/traitement.rb @@ -2,13 +2,14 @@ # # Table name: traitements # -# id :bigint not null, primary key -# instructeur_email :string -# motivation :string -# process_expired :boolean -# processed_at :datetime -# state :string -# dossier_id :bigint +# id :bigint not null, primary key +# instructeur_email :string +# motivation :string +# process_expired :boolean +# process_expired_migrated :boolean default(FALSE) +# processed_at :datetime +# state :string +# dossier_id :bigint # class Traitement < ApplicationRecord belongs_to :dossier, optional: false diff --git a/db/migrate/20211126152402_move_process_expire_to_procedures.rb b/db/migrate/20211126152402_move_process_expire_to_procedures.rb new file mode 100644 index 000000000..c38dc9e7a --- /dev/null +++ b/db/migrate/20211126152402_move_process_expire_to_procedures.rb @@ -0,0 +1,17 @@ +class MoveProcessExpireToProcedures < ActiveRecord::Migration[6.1] + include Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_column :procedures, :procedure_expires_when_termine_enabled, :boolean, default: false + add_column :traitements, :process_expired_migrated, :boolean, default: false + add_concurrent_index :procedures, :procedure_expires_when_termine_enabled + end + + def down + remove_index :procedures, name: :index_procedures_on_process_expired + remove_column :traitements, :process_expired_migrated + remove_column :procedures, :procedure_expires_when_termine_enabled + end +end diff --git a/db/schema.rb b/db/schema.rb index 64a46604c..6d8197219 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -320,12 +320,12 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.interval "conservation_extension", default: "PT0S" t.string "deleted_user_email_never_send" t.datetime "declarative_triggered_at" - t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin - t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin t.bigint "dossier_transfer_id" t.datetime "identity_updated_at" t.datetime "depose_at" t.datetime "hidden_by_user_at" + t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin + t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin t.index ["archived"], name: "index_dossiers_on_archived" t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id" t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id" @@ -646,15 +646,21 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.text "api_particulier_scopes", default: [], array: true t.jsonb "api_particulier_sources", default: {} t.boolean "instructeurs_self_management_enabled" +<<<<<<< HEAD t.bigint "zone_id" t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin +======= +>>>>>>> a6fcae97b (refactor(traitement.process_expired): move process expired to procedure) t.boolean "routing_enabled" + t.boolean "procedure_expires_when_termine_enabled", default: false + t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state" t.index ["draft_revision_id"], name: "index_procedures_on_draft_revision_id" t.index ["hidden_at"], name: "index_procedures_on_hidden_at" t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id" t.index ["path", "closed_at", "hidden_at", "unpublished_at"], name: "procedure_path_uniqueness", unique: true t.index ["path", "closed_at", "hidden_at"], name: "index_procedures_on_path_and_closed_at_and_hidden_at", unique: true + t.index ["procedure_expires_when_termine_enabled"], name: "index_procedures_on_procedure_expires_when_termine_enabled" t.index ["published_revision_id"], name: "index_procedures_on_published_revision_id" t.index ["service_id"], name: "index_procedures_on_service_id" t.index ["zone_id"], name: "index_procedures_on_zone_id" @@ -745,6 +751,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.datetime "processed_at" t.string "instructeur_email" t.boolean "process_expired" + t.boolean "process_expired_migrated", default: false t.index ["dossier_id"], name: "index_traitements_on_dossier_id" t.index ["process_expired"], name: "index_traitements_on_process_expired" end diff --git a/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake b/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake new file mode 100644 index 000000000..5a4f44df4 --- /dev/null +++ b/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake @@ -0,0 +1,21 @@ +namespace :after_party do + desc 'Deployment task: move_traitement_process_expired_to_procedure' + + task move_traitement_process_expired_to_procedure: :environment do + procedures = Procedure.joins(dossiers: :traitements).where(dossiers: {traitements: {process_expired: true, process_expired_migrated: false}}) + progress = ProgressReport.new(procedures.count) + + procedures.group(:id).find_each do |procedure| + ActiveRecord::Base.transaction do + puts "update traitements from dossier_ids: #{procedure.dossiers.ids}" + Traitement.where(id: procedure.dossiers.ids).update_all(process_expired_migrated: true) + Procedure.update(procedure_expires_when_termine_enabled: true) + progress.inc + end + end + progress.finish + + AfterParty::TaskRecord + .create version: AfterParty::TaskRecorder.new(__FILE__).timestamp + end +end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 5a68978bc..af9efb863 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -109,39 +109,12 @@ describe Dossier do end end - describe 'en_instruction_close_to_expiration' do - let(:procedure) { create(:procedure, :published, duree_conservation_dossiers_dans_ds: 6) } - let!(:young_dossier) { create(:dossier, procedure: procedure) } - let!(:expiring_dossier) { create(:dossier, :en_instruction, en_instruction_at: 175.days.ago, procedure: procedure) } - let!(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } - let!(:long_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 1.year.ago, procedure: procedure) } - - subject { Dossier.en_instruction_close_to_expiration } - - it do - is_expected.not_to include(young_dossier) - is_expected.to include(expiring_dossier) - is_expected.to include(just_expired_dossier) - is_expected.to include(long_expired_dossier) - end - - context 'when .close_to_expiration' do - subject { Dossier.close_to_expiration } - it do - is_expected.not_to include(young_dossier) - is_expected.to include(expiring_dossier) - is_expected.to include(just_expired_dossier) - is_expected.to include(long_expired_dossier) - end - end - end - describe 'termine_close_to_expiration' do - let(:procedure) { create(:procedure, :published, duree_conservation_dossiers_dans_ds: 6) } - let!(:young_dossier) { create(:dossier, :accepte, procedure: procedure, traitements: [build(:traitement, :accepte)]) } - let!(:expiring_dossier) { create(:dossier, :accepte, procedure: procedure, traitements: [build(:traitement, :accepte, processed_at: 175.days.ago)]) } - let!(:just_expired_dossier) { create(:dossier, :accepte, procedure: procedure, traitements: [build(:traitement, :accepte, processed_at: (6.months + 1.hour + 10.seconds).ago)]) } - let!(:long_expired_dossier) { create(:dossier, :accepte, procedure: procedure, traitements: [build(:traitement, :accepte, processed_at: 1.year.ago)]) } + let(:procedure) { create(:procedure, :published, duree_conservation_dossiers_dans_ds: 6, procedure_expires_when_termine_enabled: true) } + let!(:young_dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: 2.days.ago) } + let!(:expiring_dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: 175.days.ago) } + let!(:just_expired_dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: (6.months + 1.hour + 10.seconds).ago) } + let!(:long_expired_dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: 1.year.ago) } subject { Dossier.termine_close_to_expiration } From 2dfbc70d41e9fb38ff46d171a19fe7b5745e1cf1 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 1 Dec 2021 14:39:03 +0100 Subject: [PATCH 09/19] feat(instructeur#dossiers_count_summary): add counter for expirants. ignore brouillon --- .../instructeurs/procedures_controller.rb | 6 ++++- app/models/instructeur.rb | 20 +++++++++++++-- spec/models/instructeur_spec.rb | 25 ++++++++++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index dda4c0394..8c3e6a9e8 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -53,7 +53,7 @@ module Instructeurs @a_suivre_count, @suivis_count, @traites_count, @tous_count, @archives_count = current_instructeur .dossiers_count_summary(groupe_instructeur_ids) - .fetch_values('a_suivre', 'suivis', 'traites', 'tous', 'archives') + .fetch_values('a_suivre', 'suivis', 'traites', 'tous', 'archives', 'expirant') dossiers_visibles = Dossier .where(groupe_instructeur_id: groupe_instructeur_ids) @@ -72,6 +72,7 @@ module Instructeurs @termines_dossiers = dossiers_visibles.termine @all_state_dossiers = dossiers_visibles.all_state @archived_dossiers = dossiers_visibles.archived + @expirant_dossiers = dossiers_visibles.close_to_expiration @dossiers = case statut when 'a-suivre' @@ -89,6 +90,9 @@ module Instructeurs when 'archives' dossiers_count = @archives_count @archived_dossiers + when 'expirant' + dossiers_count = @archives_count + @expirant_dossiers end notifications = current_instructeur.notifications_for_groupe_instructeurs(groupe_instructeur_ids) diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index 4dd9fb139..58fa00620 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -237,8 +237,22 @@ class Instructeur < ApplicationRecord COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.instructeur_id = :instructeur_id) AS suivis, COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS traites, COUNT(DISTINCT dossiers.id) FILTER (where not archived) AS tous, - COUNT(DISTINCT dossiers.id) FILTER (where archived) AS archives + COUNT(DISTINCT dossiers.id) FILTER (where archived) AS archives, + COUNT(DISTINCT dossiers.id) FILTER (where + procedures.procedure_expires_when_termine_enabled + AND ( + dossiers.state in ('accepte', 'refuse', 'sans_suite') + AND dossiers.processed_at + dossiers.conservation_extension + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now + ) OR ( + dossiers.state in ('en_construction') + AND dossiers.en_construction_at + dossiers.conservation_extension + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now + ) + ) AS expirant FROM "dossiers" + INNER JOIN "procedure_revisions" + ON "procedure_revisions"."id" = "dossiers"."revision_id" + INNER JOIN "procedures" + ON "procedures"."id" = "procedure_revisions"."procedure_id" LEFT OUTER JOIN follows ON follows.dossier_id = dossiers.id AND follows.unfollowed_at IS NULL @@ -250,7 +264,9 @@ class Instructeur < ApplicationRecord sanitized_query = ActiveRecord::Base.sanitize_sql([ query, instructeur_id: id, - groupe_instructeur_ids: groupe_instructeur_ids + groupe_instructeur_ids: groupe_instructeur_ids, + now: Time.zone.now, + expires_in: Dossier::INTERVAL_BEFORE_EXPIRATION ]) Dossier.connection.select_all(sanitized_query).first diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index 3e28c4795..d3d8256a5 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -594,7 +594,7 @@ describe Instructeur, type: :model do describe "#dossiers_count_summary" do let(:instructeur_2) { create(:instructeur) } let(:instructeur_3) { create(:instructeur) } - let(:procedure) { create(:procedure, instructeurs: [instructeur_2, instructeur_3]) } + let(:procedure) { create(:procedure, instructeurs: [instructeur_2, instructeur_3], procedure_expires_when_termine_enabled: true) } let(:gi_1) { procedure.groupe_instructeurs.first } let(:gi_2) { procedure.groupe_instructeurs.create(label: '2') } let(:gi_3) { procedure.groupe_instructeurs.create(label: '3') } @@ -614,6 +614,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(0) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } end context 'with a new brouillon dossier' do @@ -624,6 +625,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(0) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } end context 'with a new dossier without follower' do @@ -634,6 +636,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(1) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } context 'and dossiers without follower on each of the others groups' do let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) } @@ -658,6 +661,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(1) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } context 'and another one follows the same dossier' do before do @@ -669,6 +673,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(1) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } end context 'and dossier with a follower on each of the others groups' do @@ -692,6 +697,7 @@ describe Instructeur, type: :model do it { expect(subject['a_suivre']).to eq(1) } it { expect(subject['suivis']).to eq(0) } it { expect(subject['tous']).to eq(1) } + it { expect(subject['expirant']).to eq(0) } end end @@ -703,6 +709,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(1) } it { expect(subject['tous']).to eq(1) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } context 'and terminer dossiers on each of the others groups' do let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) } @@ -715,6 +722,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(2) } it { expect(subject['tous']).to eq(2) } it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(0) } end end @@ -726,6 +734,7 @@ describe Instructeur, type: :model do it { expect(subject['traites']).to eq(0) } it { expect(subject['tous']).to eq(0) } it { expect(subject['archives']).to eq(1) } + it { expect(subject['expirant']).to eq(0) } context 'and terminer dossiers on each of the others groups' do let!(:archives_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) } @@ -734,6 +743,20 @@ describe Instructeur, type: :model do it { expect(subject['archives']).to eq(2) } end end + + context 'with an expirants dossier' do + let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) } + let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, en_construction_at: 175.days.ago, procedure: procedure) } + + before { subject } + + it { expect(subject['a_suivre']).to eq(1) } + it { expect(subject['suivis']).to eq(0) } + it { expect(subject['traites']).to eq(1) } + it { expect(subject['tous']).to eq(2) } + it { expect(subject['archives']).to eq(0) } + it { expect(subject['expirant']).to eq(2) } + end end end From d87f8b57cc06cc6d62f10fca1a343a11294fa2af Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 1 Dec 2021 17:39:47 +0100 Subject: [PATCH 10/19] feat(instructeurs/procedures#show): add dossier experiant in procedure#show --- .../instructeurs/procedures_controller.rb | 12 ++++++++---- app/models/dossier.rb | 7 +++++++ .../instructeurs/procedures/_header.html.haml | 5 +++++ .../instructeurs/procedures/show.html.haml | 3 +++ ...dd_expirants_to_procedure_presentations.rb | 10 ++++++++++ db/schema.rb | 6 +----- spec/models/dossier_spec.rb | 19 +++++++++++++++++++ 7 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index 8c3e6a9e8..b10d52297 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -17,7 +17,11 @@ module Instructeurs @dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) @dossiers_termines_count_per_procedure = dossiers.termine.group('groupe_instructeurs.procedure_id').reorder(nil).count - @dossiers_expirant_count_per_procedure = dossiers.close_to_expiration.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) +<<<<<<< HEAD + @dossiers_expirant_count_per_procedure = dossiers.termine_close_to_expiration.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) +======= + @dossiers_expirant_count_per_procedure = dossiers.termine_or_en_construction_close_to_expiration.group('groupe_instructeurs.procedure_id').count # why not reorder(nil) +>>>>>>> 2722cf295 (fixup! feat(instructeurs/procedures#show): add dossier experiant in procedure#show) groupe_ids = current_instructeur.groupe_instructeurs.pluck(:id) @followed_dossiers_count_per_procedure = current_instructeur @@ -51,7 +55,7 @@ module Instructeurs @current_filters = current_filters @displayed_fields_options, @displayed_fields_selected = procedure_presentation.displayed_fields_for_select - @a_suivre_count, @suivis_count, @traites_count, @tous_count, @archives_count = current_instructeur + @a_suivre_count, @suivis_count, @traites_count, @tous_count, @archives_count, @expirant_count = current_instructeur .dossiers_count_summary(groupe_instructeur_ids) .fetch_values('a_suivre', 'suivis', 'traites', 'tous', 'archives', 'expirant') @@ -72,7 +76,7 @@ module Instructeurs @termines_dossiers = dossiers_visibles.termine @all_state_dossiers = dossiers_visibles.all_state @archived_dossiers = dossiers_visibles.archived - @expirant_dossiers = dossiers_visibles.close_to_expiration + @expirant_dossiers = dossiers_visibles.termine_or_en_construction_close_to_expiration @dossiers = case statut when 'a-suivre' @@ -91,7 +95,7 @@ module Instructeurs dossiers_count = @archives_count @archived_dossiers when 'expirant' - dossiers_count = @archives_count + dossiers_count = @expirant_count @expirant_dossiers end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 1e41ffe4e..6d7580ffe 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -319,6 +319,13 @@ class Dossier < ApplicationRecord end end + scope :termine_or_en_construction_close_to_expiration, -> do + joins(:procedure).scoping do + interval_en_construction_close_to_expiration + .or(interval_termine_close_to_expiration) + end + end + scope :brouillon_expired, -> do state_brouillon .where("brouillon_close_to_expiration_notice_sent_at + INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_EXPIRATION }) diff --git a/app/views/instructeurs/procedures/_header.html.haml b/app/views/instructeurs/procedures/_header.html.haml index 511273910..771209d82 100644 --- a/app/views/instructeurs/procedures/_header.html.haml +++ b/app/views/instructeurs/procedures/_header.html.haml @@ -44,3 +44,8 @@ instructeur_procedure_path(procedure, statut: 'archives'), active: statut == 'archives', badge: number_with_html_delimiter(archives_count)) + + = tab_item(t('pluralize.dossiers_close_to_expiration', count: expirant_count), + instructeur_procedure_path(procedure, statut: 'expirant'), + active: statut == 'expirant', + badge: number_with_html_delimiter(expirant_count)) diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml index 1ab6d2f62..41207a162 100644 --- a/app/views/instructeurs/procedures/show.html.haml +++ b/app/views/instructeurs/procedures/show.html.haml @@ -14,6 +14,7 @@ traites_count: @traites_count, tous_count: @tous_count, archives_count: @archives_count, + expirant_count: @expirant_count, has_en_cours_notifications: @has_en_cours_notifications, has_termine_notifications: @has_termine_notifications } @@ -42,6 +43,8 @@ = link_to deleted_dossiers_instructeur_procedure_path(@procedure) do %span.icon.delete Afficher les dossiers supprimés + - if @statut == 'expirant' + %p.explication-onglet Les dossiers n'expireront pas avant la période de conservation des données. - if @filtered_sorted_paginated_ids.present? || @current_filters.count > 0 - pagination = paginate @filtered_sorted_paginated_ids diff --git a/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb b/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb new file mode 100644 index 000000000..5e5ffaeea --- /dev/null +++ b/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb @@ -0,0 +1,10 @@ +class AddExpirantsToProcedurePresentations < ActiveRecord::Migration[6.1] + def up + ProcedurePresentation.update_all(%Q(filters = filters || '{"expirant": []}')) + change_column_default :procedure_presentations, :filters, {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[], "expirant": []} + end + + def down + change_column_default :procedure_presentations, :filters, {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[]} + end +end diff --git a/db/schema.rb b/db/schema.rb index 6d8197219..125f43af3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -576,7 +576,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do create_table "procedure_presentations", id: :serial, force: :cascade do |t| t.integer "assign_to_id" t.jsonb "sort", default: {"order"=>"desc", "table"=>"notifications", "column"=>"notifications"}, null: false - t.jsonb "filters", default: {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[]}, null: false + t.jsonb "filters", default: {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[], "expirant"=>[]}, null: false t.datetime "created_at" t.datetime "updated_at" t.jsonb "displayed_fields", default: [{"label"=>"Demandeur", "table"=>"user", "column"=>"email"}], null: false @@ -646,11 +646,7 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.text "api_particulier_scopes", default: [], array: true t.jsonb "api_particulier_sources", default: {} t.boolean "instructeurs_self_management_enabled" -<<<<<<< HEAD t.bigint "zone_id" - t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin -======= ->>>>>>> a6fcae97b (refactor(traitement.process_expired): move process expired to procedure) t.boolean "routing_enabled" t.boolean "procedure_expires_when_termine_enabled", default: false t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index af9efb863..674cddb04 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -107,6 +107,15 @@ describe Dossier do is_expected.to include(long_expired_dossier) end end + context 'when .termine_or_en_construction_close_to_expiration' do + subject { Dossier.termine_or_en_construction_close_to_expiration } + it do + is_expected.not_to include(young_dossier) + is_expected.to include(expiring_dossier) + is_expected.to include(just_expired_dossier) + is_expected.to include(long_expired_dossier) + end + end end describe 'termine_close_to_expiration' do @@ -134,6 +143,16 @@ describe Dossier do is_expected.to include(long_expired_dossier) end end + + context 'when .close_to_expiration' do + subject { Dossier.termine_or_en_construction_close_to_expiration } + it do + is_expected.not_to include(young_dossier) + is_expected.to include(expiring_dossier) + is_expected.to include(just_expired_dossier) + is_expected.to include(long_expired_dossier) + end + end end describe 'with_notifications' do From 1bb868714c591b5053dba9ec19befdb3ca9c8525 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 2 Dec 2021 14:21:39 +0100 Subject: [PATCH 11/19] fix(spec/lint/review): lint and fix spec of previous commits, also fix based on tchak feedback --- .../instructeurs/procedures_controller.rb | 6 +--- app/models/dossier.rb | 3 +- .../expired_dossiers_deletion_service.rb | 1 - ...dd_expirants_to_procedure_presentations.rb | 4 +-- ...aitement_process_expired_to_procedure.rake | 4 +-- spec/factories/dossier.rb | 2 ++ spec/models/instructeur_spec.rb | 1 - .../expired_dossiers_deletion_service_spec.rb | 31 ++++++++++--------- .../_expiration_banner.html.haml_spec.rb | 17 +++++++--- 9 files changed, 36 insertions(+), 33 deletions(-) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index b10d52297..9e956a375 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -15,13 +15,9 @@ module Instructeurs dossiers = current_instructeur.dossiers.joins(:groupe_instructeur) @dossiers_count_per_procedure = dossiers.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count - @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) + @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count # why not reorder(nil) @dossiers_termines_count_per_procedure = dossiers.termine.group('groupe_instructeurs.procedure_id').reorder(nil).count -<<<<<<< HEAD - @dossiers_expirant_count_per_procedure = dossiers.termine_close_to_expiration.group('groupe_instructeurs.procedure_id').count #why not reorder(nil) -======= @dossiers_expirant_count_per_procedure = dossiers.termine_or_en_construction_close_to_expiration.group('groupe_instructeurs.procedure_id').count # why not reorder(nil) ->>>>>>> 2722cf295 (fixup! feat(instructeurs/procedures#show): add dossier experiant in procedure#show) groupe_ids = current_instructeur.groupe_instructeurs.pluck(:id) @followed_dossiers_count_per_procedure = current_instructeur diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 6d7580ffe..0487959ef 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -24,7 +24,6 @@ # last_commentaire_updated_at :datetime # motivation :text # private_search_terms :text -# process_expired :boolean default(FALSE) # processed_at :datetime # search_terms :text # state :string @@ -297,7 +296,7 @@ class Dossier < ApplicationRecord end scope :interval_termine_close_to_expiration, -> do state_termine - .where(procedures: { procedure_expires_when_termine_enabled: true}) + .where(procedures: { procedure_expires_when_termine_enabled: true }) .where("dossiers.processed_at + dossiers.conservation_extension + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION }) end diff --git a/app/services/expired_dossiers_deletion_service.rb b/app/services/expired_dossiers_deletion_service.rb index a7916d23c..f3df5b364 100644 --- a/app/services/expired_dossiers_deletion_service.rb +++ b/app/services/expired_dossiers_deletion_service.rb @@ -95,7 +95,6 @@ class ExpiredDossiersDeletionService deleted_dossier_ids << dossier.id end end - user_notifications.each do |(email, dossier_ids)| dossier_ids = dossier_ids.intersection(deleted_dossier_ids) if dossier_ids.present? diff --git a/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb b/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb index 5e5ffaeea..0a178ab7b 100644 --- a/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb +++ b/db/migrate/20211201135804_add_expirants_to_procedure_presentations.rb @@ -1,10 +1,10 @@ class AddExpirantsToProcedurePresentations < ActiveRecord::Migration[6.1] def up ProcedurePresentation.update_all(%Q(filters = filters || '{"expirant": []}')) - change_column_default :procedure_presentations, :filters, {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[], "expirant": []} + change_column_default :procedure_presentations, :filters, { "tous" => [], "suivis" => [], "traites" => [], "a-suivre" => [], "archives" => [], "expirant": [] } end def down - change_column_default :procedure_presentations, :filters, {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[]} + change_column_default :procedure_presentations, :filters, { "tous" => [], "suivis" => [], "traites" => [], "a-suivre" => [], "archives" => [] } end end diff --git a/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake b/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake index 5a4f44df4..8fb88f00f 100644 --- a/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake +++ b/lib/tasks/deployment/20211126152402_move_traitement_process_expired_to_procedure.rake @@ -2,14 +2,14 @@ namespace :after_party do desc 'Deployment task: move_traitement_process_expired_to_procedure' task move_traitement_process_expired_to_procedure: :environment do - procedures = Procedure.joins(dossiers: :traitements).where(dossiers: {traitements: {process_expired: true, process_expired_migrated: false}}) + procedures = Procedure.joins(dossiers: :traitements).where(dossiers: { traitements: { process_expired: true, process_expired_migrated: false } }) progress = ProgressReport.new(procedures.count) procedures.group(:id).find_each do |procedure| ActiveRecord::Base.transaction do puts "update traitements from dossier_ids: #{procedure.dossiers.ids}" Traitement.where(id: procedure.dossiers.ids).update_all(process_expired_migrated: true) - Procedure.update(procedure_expires_when_termine_enabled: true) + procedure.update(procedure_expires_when_termine_enabled: true) progress.inc end end diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb index 6bee4d8d0..48ef7ced9 100644 --- a/spec/factories/dossier.rb +++ b/spec/factories/dossier.rb @@ -135,10 +135,12 @@ FactoryBot.define do if processed_at.present? dossier.en_construction_at ||= processed_at - 2.minutes dossier.en_instruction_at ||= processed_at - 1.minute + dossier.processed_at = processed_at dossier.traitements.accepter(motivation: evaluator.motivation, processed_at: processed_at) else dossier.en_construction_at ||= dossier.created_at + 1.minute dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute + dossier.processed_at = dossier.en_instruction_at + 1.minute dossier.traitements.accepter(motivation: evaluator.motivation, processed_at: dossier.en_instruction_at + 1.minute) end dossier.save! diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index d3d8256a5..7cdfd8304 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -747,7 +747,6 @@ describe Instructeur, type: :model do context 'with an expirants dossier' do let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) } let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, en_construction_at: 175.days.ago, procedure: procedure) } - before { subject } it { expect(subject['a_suivre']).to eq(1) } diff --git a/spec/services/expired_dossiers_deletion_service_spec.rb b/spec/services/expired_dossiers_deletion_service_spec.rb index 69a5944f1..a2a098713 100644 --- a/spec/services/expired_dossiers_deletion_service_spec.rb +++ b/spec/services/expired_dossiers_deletion_service_spec.rb @@ -2,8 +2,9 @@ describe ExpiredDossiersDeletionService do let(:warning_period) { 1.month + 5.days } let(:conservation_par_defaut) { 3.months } let(:user) { create(:user) } - let(:procedure) { create(:procedure, :published) } - let(:procedure_2) { create(:procedure, :published) } + let(:procedure_opts) { {} } + let(:procedure) { create(:procedure, :published, procedure_opts) } + let(:procedure_2) { create(:procedure, :published, procedure_opts) } let(:reference_date) { Date.parse("March 8") } describe '#process_expired_dossiers_brouillon' do @@ -273,19 +274,18 @@ describe ExpiredDossiersDeletionService do describe '#send_termine_expiration_notices' do before { Timecop.freeze(reference_date) } after { Timecop.return } - - before do - Flipper.enable(:procedure_process_expired_dossiers_termine, procedure) - Flipper.enable(:procedure_process_expired_dossiers_termine, procedure_2) + let(:procedure_opts) do + { + procedure_expires_when_termine_enabled: true + } end - before do allow(DossierMailer).to receive(:notify_near_deletion_to_user).and_call_original allow(DossierMailer).to receive(:notify_near_deletion_to_administration).and_call_original end context 'with a single dossier' do - let!(:dossier) { create(:dossier, :accepte, :followed, procedure: procedure, processed_at: processed_at) } + let!(:dossier) { create(:dossier, :followed, state: :accepte, procedure: procedure, processed_at: processed_at) } before { ExpiredDossiersDeletionService.send_termine_expiration_notices } @@ -311,8 +311,8 @@ describe ExpiredDossiersDeletionService do end context 'with 2 dossiers to notice' do - let!(:dossier_1) { create(:dossier, :accepte, procedure: procedure, user: user, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } - let!(:dossier_2) { create(:dossier, :accepte, procedure: procedure_2, user: user, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } + let!(:dossier_1) { create(:dossier, state: :accepte, procedure: procedure, user: user, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } + let!(:dossier_2) { create(:dossier, state: :accepte, procedure: procedure_2, user: user, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } let!(:instructeur) { create(:instructeur) } @@ -331,7 +331,7 @@ describe ExpiredDossiersDeletionService do context 'when an instructeur is also administrateur' do let!(:administrateur) { procedure.administrateurs.first } - let!(:dossier) { create(:dossier, :accepte, procedure: procedure, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } + let!(:dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } before do administrateur.instructeur.followed_dossiers << dossier @@ -348,9 +348,10 @@ describe ExpiredDossiersDeletionService do before { Timecop.freeze(reference_date) } after { Timecop.return } - before do - Flipper.enable(:procedure_process_expired_dossiers_termine, procedure) - Flipper.enable(:procedure_process_expired_dossiers_termine, procedure_2) + let(:procedure_opts) do + { + procedure_expires_when_termine_enabled: true + } end before do @@ -359,7 +360,7 @@ describe ExpiredDossiersDeletionService do end context 'with a single dossier' do - let!(:dossier) { create(:dossier, :accepte, :followed, procedure: procedure, termine_close_to_expiration_notice_sent_at: notice_sent_at) } + let!(:dossier) { create(:dossier, :followed, :accepte, procedure: procedure, termine_close_to_expiration_notice_sent_at: notice_sent_at) } let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) } before { ExpiredDossiersDeletionService.delete_expired_termine_and_notify } diff --git a/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb b/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb index 2f758db4e..82cae47b6 100644 --- a/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb +++ b/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb @@ -1,6 +1,13 @@ describe 'shared/dossiers/expiration_banner.html.haml', type: :view do include DossierHelper - let(:dossier) { build(:dossier, state, attributes.merge(id: 1, state: state)) } + + let(:dossier) do + create(:dossier, state, attributes.merge( + id: 1, + state: state, + procedure: create(:procedure, procedure_expires_when_termine_enabled: expiration_enabled) + )) + end let(:i18n_key_state) { state } subject do render('shared/dossiers/expiration_banner.html.haml', @@ -8,8 +15,8 @@ describe 'shared/dossiers/expiration_banner.html.haml', type: :view do current_user: build(:user)) end - context 'with procedure having procedure_process_expired_dossiers_termine not enabled' do - before { allow(dossier.procedure).to receive(:feature_enabled?).with(:procedure_process_expired_dossiers_termine).and_return(false) } + context 'with procedure having procedure_expires_when_termine_enabled not enabled' do + let(:expiration_enabled) { false } let(:attributes) { { processed_at: 6.months.ago } } let(:state) { :accepte } @@ -18,8 +25,8 @@ describe 'shared/dossiers/expiration_banner.html.haml', type: :view do end end - context 'with procedure having procedure_process_expired_dossiers_termine enabled' do - before { allow(dossier.procedure).to receive(:feature_enabled?).with(:procedure_process_expired_dossiers_termine).and_return(true) } + context 'with procedure having procedure_expires_when_termine_enabled enabled' do + let(:expiration_enabled) { true } context 'with dossier.brouillon?' do let(:attributes) { { created_at: 6.months.ago } } From 8e9b15aef4887d14c5dfe3a5f7bd5c670c1bcf3d Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 2 Dec 2021 15:54:18 +0100 Subject: [PATCH 12/19] clean(expiration_banner): dedicated to user not shared --- app/views/shared/dossiers/_header.html.haml | 2 +- .../{shared => users}/dossiers/_expiration_banner.html.haml | 0 app/views/users/dossiers/show/_header.html.haml | 2 +- .../dossiers/_expiration_banner.html.haml_spec.rb | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename app/views/{shared => users}/dossiers/_expiration_banner.html.haml (100%) rename spec/views/{shared => users}/dossiers/_expiration_banner.html.haml_spec.rb (95%) diff --git a/app/views/shared/dossiers/_header.html.haml b/app/views/shared/dossiers/_header.html.haml index c34c17f10..dbffd3434 100644 --- a/app/views/shared/dossiers/_header.html.haml +++ b/app/views/shared/dossiers/_header.html.haml @@ -6,7 +6,7 @@ = t('views.users.dossiers.show.header.dossier_number', dossier_id: dossier.id) = t('views.users.dossiers.show.header.created_date', date_du_dossier: I18n.l(dossier.created_at)) - = render(partial: 'shared/dossiers/expiration_banner', locals: {dossier: dossier}) + = render(partial: 'users/dossiers/expiration_banner', locals: {dossier: dossier}) .header-actions - if current_user.owns?(dossier) diff --git a/app/views/shared/dossiers/_expiration_banner.html.haml b/app/views/users/dossiers/_expiration_banner.html.haml similarity index 100% rename from app/views/shared/dossiers/_expiration_banner.html.haml rename to app/views/users/dossiers/_expiration_banner.html.haml diff --git a/app/views/users/dossiers/show/_header.html.haml b/app/views/users/dossiers/show/_header.html.haml index 31f4bf110..1a4caf516 100644 --- a/app/views/users/dossiers/show/_header.html.haml +++ b/app/views/users/dossiers/show/_header.html.haml @@ -10,7 +10,7 @@ - if dossier.en_construction_at.present? = t('views.users.dossiers.show.header.submit_date', date_du_dossier: I18n.l(dossier.en_construction_at)) - = render(partial: 'shared/dossiers/expiration_banner', locals: {dossier: dossier}) + = render(partial: 'users/dossiers/expiration_banner', locals: {dossier: dossier}) - if current_user.owns?(dossier) diff --git a/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb b/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb similarity index 95% rename from spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb rename to spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb index 82cae47b6..30d3bef90 100644 --- a/spec/views/shared/dossiers/_expiration_banner.html.haml_spec.rb +++ b/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb @@ -1,4 +1,4 @@ -describe 'shared/dossiers/expiration_banner.html.haml', type: :view do +describe 'users/dossiers/expiration_banner.html.haml', type: :view do include DossierHelper let(:dossier) do @@ -10,7 +10,7 @@ describe 'shared/dossiers/expiration_banner.html.haml', type: :view do end let(:i18n_key_state) { state } subject do - render('shared/dossiers/expiration_banner.html.haml', + render('users/dossiers/expiration_banner.html.haml', dossier: dossier, current_user: build(:user)) end From 22531560d855fe7d9a9c05581435e90257d8d5af Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 2 Dec 2021 15:56:34 +0100 Subject: [PATCH 13/19] feat(tabs.expirants): re-order so it comes before deleted dossiers --- .../instructeurs/procedures_controller.rb | 4 +-- .../instructeurs/procedures/_header.html.haml | 10 +++--- .../instructeurs/procedures/_list.html.haml | 19 ++++++----- app/views/users/dossiers/index.html.haml | 12 +++---- config/locales/fr.yml | 6 ++-- .../procedures/_header.html.haml_spec.rb | 32 +++++++++++++++++++ .../procedures/_list.html.haml_spec.rb | 30 +++++++++++++++++ 7 files changed, 90 insertions(+), 23 deletions(-) create mode 100644 spec/views/instructeur/procedures/_header.html.haml_spec.rb create mode 100644 spec/views/instructeur/procedures/_list.html.haml_spec.rb diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index 9e956a375..e9954280f 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -34,8 +34,8 @@ module Instructeurs 'suivis' => @followed_dossiers_count_per_procedure.sum { |_, v| v }, 'traités' => @dossiers_termines_count_per_procedure.sum { |_, v| v }, 'dossiers' => @dossiers_count_per_procedure.sum { |_, v| v }, - 'archivés' => @dossiers_archived_count_per_procedure.sum { |_, v| v }, - 'expirant' => @dossiers_expirant_count_per_procedure.sum { |_, v| v } + 'expirant' => @dossiers_expirant_count_per_procedure.sum { |_, v| v }, + 'archivés' => @dossiers_archived_count_per_procedure.sum { |_, v| v } } @procedure_ids_en_cours_with_notifications = current_instructeur.procedure_ids_with_notifications(:en_cours) diff --git a/app/views/instructeurs/procedures/_header.html.haml b/app/views/instructeurs/procedures/_header.html.haml index 771209d82..66be03776 100644 --- a/app/views/instructeurs/procedures/_header.html.haml +++ b/app/views/instructeurs/procedures/_header.html.haml @@ -40,12 +40,14 @@ active: statut == 'tous', badge: number_with_html_delimiter(tous_count)) + - if procedure.procedure_expires_when_termine_enabled + = tab_item(t('pluralize.dossiers_close_to_expiration', count: expirant_count), + instructeur_procedure_path(procedure, statut: 'expirant'), + active: statut == 'expirant', + badge: number_with_html_delimiter(expirant_count)) + = tab_item(t('pluralize.archived', count: archives_count), instructeur_procedure_path(procedure, statut: 'archives'), active: statut == 'archives', badge: number_with_html_delimiter(archives_count)) - = tab_item(t('pluralize.dossiers_close_to_expiration', count: expirant_count), - instructeur_procedure_path(procedure, statut: 'expirant'), - active: statut == 'expirant', - badge: number_with_html_delimiter(expirant_count)) diff --git a/app/views/instructeurs/procedures/_list.html.haml b/app/views/instructeurs/procedures/_list.html.haml index 96c25d2b2..6f60a13af 100644 --- a/app/views/instructeurs/procedures/_list.html.haml +++ b/app/views/instructeurs/procedures/_list.html.haml @@ -44,6 +44,17 @@ = number_with_html_delimiter(dossier_count) .stats-legend = t('pluralize.case', count: dossier_count) + + - if p.procedure_expires_when_termine_enabled + %li + %object + = link_to(instructeur_procedure_path(p, statut: 'expirant')) do + - expirant_count = dossiers_expirant_count_per_procedure[p.id] || 0 + .stats-number + = number_with_html_delimiter(expirant_count) + .stats-legend + = t('pluralize.dossiers_close_to_expiration', count: expirant_count) + %li %object = link_to(instructeur_procedure_path(p, statut: 'archives')) do @@ -52,14 +63,6 @@ = number_with_html_delimiter(archived_count) .stats-legend = t('pluralize.archived', count: archived_count) - %li - %object - = link_to(instructeur_procedure_path(p, statut: 'expirant')) do - - expirant_count = dossiers_expirant_count_per_procedure[p.id] || 0 - .stats-number - = number_with_html_delimiter(expirant_count) - .stats-legend - = t('pluralize.dossiers_close_to_expiration', count: expirant_count) - if p.close? .procedure-status diff --git a/app/views/users/dossiers/index.html.haml b/app/views/users/dossiers/index.html.haml index 4cb77fe2d..d6d0bca8a 100644 --- a/app/views/users/dossiers/index.html.haml +++ b/app/views/users/dossiers/index.html.haml @@ -32,6 +32,12 @@ active: @statut == 'dossiers-invites', badge: number_with_html_delimiter(@dossiers_invites.count)) + - if @dossiers_close_to_expiration.count > 0 + = tab_item(t('pluralize.dossiers_close_to_expiration', count: @dossiers_close_to_expiration.count), + dossiers_path(statut: 'dossiers-expirant'), + active: @statut == 'dossiers-expirant', + badge: number_with_html_delimiter(@dossiers_close_to_expiration.count)) + - if @dossiers_supprimes.present? = tab_item(t('pluralize.dossiers_supprimes', count: @dossiers_supprimes.count), dossiers_path(statut: 'dossiers-supprimes'), @@ -44,12 +50,6 @@ active: @statut == 'dossiers-transferes', badge: number_with_html_delimiter(@dossier_transfers.count)) - - if @dossiers_close_to_expiration.count > 0 - = tab_item(t('pluralize.dossiers_close_to_expiration', count: @dossiers_close_to_expiration.count), - dossiers_path(statut: 'dossiers-expirant'), - active: @statut == 'dossiers-expirant', - badge: number_with_html_delimiter(@dossiers_close_to_expiration.count)) - .container - if @statut == "en-cours" = render partial: "dossiers_list", locals: { dossiers: @user_dossiers } diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a46c36683..ae571a661 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -365,9 +365,9 @@ fr: one: demande de transfert other: demandes de transfert dossiers_close_to_expiration: - zero: dossier expirant - one: dossier expirant - other: dossiers expirant + zero: expirant + one: expirant + other: expirant dossier_trouve: zero: 0 dossier trouvé one: 1 dossier trouvé diff --git a/spec/views/instructeur/procedures/_header.html.haml_spec.rb b/spec/views/instructeur/procedures/_header.html.haml_spec.rb new file mode 100644 index 000000000..a9da674d0 --- /dev/null +++ b/spec/views/instructeur/procedures/_header.html.haml_spec.rb @@ -0,0 +1,32 @@ +describe 'instructeurs/procedures/_header.html.haml', type: :view do + let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled)} + + subject do + render('instructeurs/procedures/header.html.haml', + procedure: procedure, + statut: 'tous', + a_suivre_count: 0, + suivis_count: 0, + traites_count: 0, + tous_count: 0, + archives_count: 0, + expirant_count: 0, + has_en_cours_notifications: false, + has_termine_notifications: false, + current_instructeur: build_stubbed(:instructeur)) + end + + context 'when procedure_expires_when_termine_enabled is true' do + let(:expiration_enabled) { true } + it 'contains link to expiring dossiers within procedure' do + expect(subject).to have_selector(%Q(a[href="#{instructeur_procedure_path(procedure, statut: 'expirant')}"]), count: 1) + end + end + + context 'when procedure_expires_when_termine_enabled is false' do + let(:expiration_enabled) { false } + it 'does not contain link to expiring dossiers within procedure' do + expect(subject).to have_selector(%Q(a[href="#{instructeur_procedure_path(procedure, statut: 'expirant')}"]), count: 0) + end + end +end diff --git a/spec/views/instructeur/procedures/_list.html.haml_spec.rb b/spec/views/instructeur/procedures/_list.html.haml_spec.rb new file mode 100644 index 000000000..513013386 --- /dev/null +++ b/spec/views/instructeur/procedures/_list.html.haml_spec.rb @@ -0,0 +1,30 @@ +describe 'instructeurs/procedures/_list.html.haml', type: :view do + let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled)} + + subject do + render('instructeurs/procedures/list.html.haml', + p: procedure, + dossiers_count_per_procedure: 5, + dossiers_a_suivre_count_per_procedure: 2, + dossiers_archived_count_per_procedure: 1, + dossiers_termines_count_per_procedure: 1, + dossiers_expirant_count_per_procedure: 0, + followed_dossiers_count_per_procedure: 0, + procedure_ids_en_cours_with_notifications: [], + procedure_ids_termines_with_notifications: []) + end + + context 'when procedure_expires_when_termine_enabled is true' do + let(:expiration_enabled) { true } + it 'contains link to expiring dossiers within procedure' do + expect(subject).to have_selector(%Q(a[href="#{instructeur_procedure_path(procedure, statut: 'expirant')}"]), count: 1) + end + end + + context 'when procedure_expires_when_termine_enabled is false' do + let(:expiration_enabled) { false } + it 'does not contain link to expiring dossiers within procedure' do + expect(subject).to have_selector(%Q(a[href="#{instructeur_procedure_path(procedure, statut: 'expirant')}"]), count: 0) + end + end +end From d8a8d1fdab1fca70d6329d6f05ee19575ff50f67 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 2 Dec 2021 16:19:17 +0100 Subject: [PATCH 14/19] feat(instructeur/dossier/header/_expiration_banner): split trads and add dedicated expiration banner for instructeur. also enhance wording to include duree conservation + extension_conservation feat(expiration_banner): enhance wording of expiration feat(dossiers/expiration_banner): enhance wording regarding expiration to include duree_conservation_dossiers_dans_ds + extension_conservation, also add spec on expiration_banner for instructeur --- app/models/dossier.rb | 4 ++ .../dossiers/_expiration_banner.html.haml | 26 ++++++++ .../instructeurs/dossiers/_header.html.haml | 3 + .../dossiers/_expiration_banner.html.haml | 16 ++--- config/locales/en.yml | 4 +- config/locales/fr.yml | 4 +- config/locales/shared.en.yml | 17 ++--- config/locales/shared.fr.yml | 18 ++--- .../locales/views/instructeurs/header/en.yml | 11 ++++ .../locales/views/instructeurs/header/fr.yml | 11 ++++ config/locales/views/users/header/en.yml | 11 ++++ config/locales/views/users/header/fr.yml | 11 ++++ spec/models/instructeur_spec.rb | 4 +- .../_expiration_banner.html.haml_spec.rb | 66 +++++++++++++++++++ .../procedures/_header.html.haml_spec.rb | 7 +- .../procedures/_list.html.haml_spec.rb | 2 +- .../_expiration_banner.html.haml_spec.rb | 14 ++-- 17 files changed, 182 insertions(+), 47 deletions(-) create mode 100644 app/views/instructeurs/dossiers/_expiration_banner.html.haml create mode 100644 config/locales/views/instructeurs/header/en.yml create mode 100644 config/locales/views/instructeurs/header/fr.yml create mode 100644 config/locales/views/users/header/en.yml create mode 100644 config/locales/views/users/header/fr.yml create mode 100644 spec/views/instructeur/dossiers/_expiration_banner.html.haml_spec.rb diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 0487959ef..c40d6be2e 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -646,6 +646,10 @@ class Dossier < ApplicationRecord parts.join end + def duree_totale_conservation_in_months + procedure.duree_conservation_dossiers_dans_ds + (conservation_extension / 1.month.to_i) + end + def avis_for_instructeur(instructeur) if instructeur.dossiers.include?(self) avis.order(created_at: :asc) diff --git a/app/views/instructeurs/dossiers/_expiration_banner.html.haml b/app/views/instructeurs/dossiers/_expiration_banner.html.haml new file mode 100644 index 000000000..0dee1a5ea --- /dev/null +++ b/app/views/instructeurs/dossiers/_expiration_banner.html.haml @@ -0,0 +1,26 @@ +-# small expires mention +- if dossier.expirable? + %p.expires_at.mb-2 + + %small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) + -# big banner warning + - if dossier.close_to_expiration? + .card.warning.mb-3 + .card-title= t('instructeurs.dossiers.header.banner.title') + %p + - if dossier.brouillon? + = t('instructeurs.dossiers.header.banner.states.brouillon') + - elsif dossier.en_construction? + = t('instructeurs.dossiers.header.banner.states.en_construction') + - elsif dossier.termine? + = t('instructeurs.dossiers.header.banner.states.termine') + + - if dossier.expiration_can_be_extended? + %br + = button_to t('instructeurs.dossiers.header.banner.button_delay_expiration'), users_dossier_repousser_expiration_path(dossier), class: 'button secondary mt-2' + + +- else + %p.expires_at_en_instruction + %small= t("shared.dossiers.header.expires_at.en_instruction") + diff --git a/app/views/instructeurs/dossiers/_header.html.haml b/app/views/instructeurs/dossiers/_header.html.haml index a2d2de025..19e8073f5 100644 --- a/app/views/instructeurs/dossiers/_header.html.haml +++ b/app/views/instructeurs/dossiers/_header.html.haml @@ -9,9 +9,12 @@ = dossier.procedure.libelle.truncate_words(10) %li = "Dossier nº #{dossier.id}" + .header-actions = render partial: 'instructeurs/dossiers/header_actions', locals: { dossier: dossier } + = render(partial: 'instructeurs/dossiers/expiration_banner', locals: {dossier: dossier}) + %ul.tabs - notifications_summary = current_instructeur.notifications_for_dossier(dossier) diff --git a/app/views/users/dossiers/_expiration_banner.html.haml b/app/views/users/dossiers/_expiration_banner.html.haml index 8f4689117..ab04fea8f 100644 --- a/app/views/users/dossiers/_expiration_banner.html.haml +++ b/app/views/users/dossiers/_expiration_banner.html.haml @@ -1,22 +1,22 @@ -# small expires mention - if dossier.expirable? - %p.expires_at - %small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier)) + %p.expires_at.mb-2 + %small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) -# big banner warning - if dossier.close_to_expiration? - .card.warning.mt-2.mb-3 - .card-title= t('shared.dossiers.header.banner.title') + .card.warning.mb-3 + .card-title= t('users.dossiers.header.banner.title') %p - if dossier.brouillon? - = t('shared.dossiers.header.banner.states.brouillon') + = t('users.dossiers.header.banner.states.brouillon') - elsif dossier.en_construction? - = t('shared.dossiers.header.banner.states.en_construction') + = t('users.dossiers.header.banner.states.en_construction') - elsif dossier.termine? - = t('shared.dossiers.header.banner.states.termine') + = t('users.dossiers.header.banner.states.termine') - if dossier.expiration_can_be_extended? %br - = button_to t('shared.dossiers.header.banner.button_delay_expiration'), users_dossier_repousser_expiration_path(dossier), class: 'button secondary mt-2' + = button_to t('users.dossiers.header.banner.button_delay_expiration'), users_dossier_repousser_expiration_path(dossier), class: 'button secondary mt-2' - else diff --git a/config/locales/en.yml b/config/locales/en.yml index 37d74c65f..88f1b2139 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -134,11 +134,13 @@ en: edit_identity: "Edit identity data" instructeurs: dossiers: + archived_dossier: "This file will be kept for an additional month" deleted_by_user: "File deleted by user" avis: introduction_file_explaination: "File attached to the request for advice" users: dossiers: + archived_dossier: "Your file will be kept %{duree_conservation_dossiers_dans_ds} more months" autosave: autosave_draft: Your draft is automatically saved. more_infos: More informations @@ -382,8 +384,6 @@ en: ask_deletion: undergoingreview: "Your file is undergoing review. It is no longer possible to delete your file. To cancel the undergoingreview contact the adminitration via the mailbox." deleted_dossier: "Your file has been successfully deleted" - extend_conservation: - archived_dossier: "Your file will be archived for an additional month" update_brouillon: draft_saved: "Your draft has been saved." etablissement: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index ae571a661..81afc6b1d 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -130,6 +130,7 @@ fr: edit_identity: "Modifier l’identité" instructeurs: dossiers: + archived_dossier: "Le dossier sera conservé 1 mois supplémentaire" deleted_by_user: "Dossier supprimé par l'usager" avis: introduction_file_explaination: "Fichier joint à la demande d’avis" @@ -389,13 +390,12 @@ fr: test_procedure: "Ce dossier est déposé sur une démarche en test. Toute modification de la démarche par l’administrateur (ajout d'un champ, publication de la démarche...) entraînera sa suppression." no_access: "Vous n’avez pas accès à ce dossier" no_longer_editable: "Votre dossier ne peut plus être modifié" + archived_dossier: "Votre dossier sera conservé %{duree_conservation_dossiers_dans_ds} mois supplémentaire" create_commentaire: message_send: "Votre message a bien été envoyé à l’instructeur en charge de votre dossier." ask_deletion: undergoingreview: "L’instruction de votre dossier a commencé, il n’est plus possible de supprimer votre dossier. Si vous souhaitez annuler l’instruction contactez votre administration par la messagerie de votre dossier." deleted_dossier: "Votre dossier a bien été supprimé." - extend_conservation: - archived_dossier: "Votre dossier sera conservé un mois supplémentaire" update_brouillon: draft_saved: "Votre brouillon a bien été sauvegardé." etablissement: diff --git a/config/locales/shared.en.yml b/config/locales/shared.en.yml index 718513321..3f0316661 100644 --- a/config/locales/shared.en.yml +++ b/config/locales/shared.en.yml @@ -9,19 +9,12 @@ en: code_postal_notice: It is usually composed of 5 digits. header: expires_at: - brouillon: "Expires at %{date}" - en_construction: "Expires at %{date}" + brouillon: "Expires at %{date} (%{duree_conservation_totale} months after the creation of this file)" + en_construction: "Expires at %{date} (%{duree_conservation_totale} months after the last la edition of this file)" en_instruction: "This file is being instructed, the administration will answer as soon as possible" - accepte: "Expires at %{date}" - refuse: "Expires at %{date}" - sans_suite: "Expires at %{date}" - banner: - title: Your file will expire - states: - brouillon: Your file is still in draft and will soon expire. So it will be deleted soon without being instructed. If you want to pursue your procedure you can submit it now. Otherwise you are able to delay its expiration by clicking on the underneath button. - en_construction: Your file is pending for instruction. The maximum delay is 6 months, but your can extend the duration by a month by clicking on the underneath button. - termine: Your file had been processed and will soon expire.So it will be deleted soon. If you want to keep it, your can dowload a PDF file of it. - button_delay_expiration: "Delay deletion" + accepte: "Expires at %{date} (%{duree_conservation_totale} months after the acceptation of this file)" + refuse: "Expires at %{date} (%{duree_conservation_totale} months after the rejection of this file)" + sans_suite: "Expires at %{date} (%{duree_conservation_totale} months after this file had been closed)" champs: cnaf: show: diff --git a/config/locales/shared.fr.yml b/config/locales/shared.fr.yml index cbeb937df..538aeb966 100644 --- a/config/locales/shared.fr.yml +++ b/config/locales/shared.fr.yml @@ -9,19 +9,13 @@ fr: code_postal_notice: Il est généralement composé de 5 chiffres. header: expires_at: - brouillon: "Expirera le %{date}" - en_construction: "Expirera le %{date}" + brouillon: "Expirera le %{date} (%{duree_conservation_totale} mois après la création du dossier)" + en_construction: "Expirera le %{date} (%{duree_conservation_totale} mois après la dernière date d'édition)" en_instruction: "Ce dossier est en instruction, il n'expirera pas" - accepte: "Expirera le %{date}" - refuse: "Expirera le %{date}" - sans_suite: "Expirera le %{date}" - banner: - title: Votre dossier va expirer - states: - brouillon: Votre dossier est en brouillon, mais va bientôt expirer. Cela signifie qu’il va bientôt être supprimé sans avoir été déposé. Si vous souhaitez le conserver afin de poursuivre la démarche, vous pouvez le conserver un mois de plus en cliquant sur le bouton ci-dessous. - en_construction: Votre dossier est en attente de prise en charge par l'administration. Le delais de prise en charge maximale est de 6 mois. Vous pouvez toutefois entendre cette durée d'un mois en cliquant sur le bouton suivant. - termine: Le traitement de votre dossier est terminé, mais il va bientôt expirer. Cela signifie qu’il va bientôt être supprimé. Si vous souhaitez conserver une trace, vous pouvez le télécharger au format PDF. - button_delay_expiration: "Repousser sa suppression" + accepte: "Expirera le %{date} (%{duree_conservation_totale} mois après l'acceptation du dossier)" + refuse: "Expirera le %{date} (%{duree_conservation_totale} mois après le refus du dossier)" + sans_suite: "Expirera le %{date} (%{duree_conservation_totale} mois après que le dossier aie été classé sans suite)" + champs: cnaf: diff --git a/config/locales/views/instructeurs/header/en.yml b/config/locales/views/instructeurs/header/en.yml new file mode 100644 index 000000000..44ee0126a --- /dev/null +++ b/config/locales/views/instructeurs/header/en.yml @@ -0,0 +1,11 @@ +en: + instructeurs: + dossiers: + header: + banner: + title: This file will expire + states: + brouillon: "" # not applicable, instructeur does not see brouillons + en_construction: This file is pending for instruction. The maximum delay is 6 months, you can extend the duration by a month by clicking on the underneath button. + termine: This file had been processed and will soon expire. So it will be deleted soon. If you want to keep it, you can dowload a PDF file of it. + button_delay_expiration: "Delay deletion" diff --git a/config/locales/views/instructeurs/header/fr.yml b/config/locales/views/instructeurs/header/fr.yml new file mode 100644 index 000000000..2248ed793 --- /dev/null +++ b/config/locales/views/instructeurs/header/fr.yml @@ -0,0 +1,11 @@ +fr: + instructeurs: + dossiers: + header: + banner: + title: Ce dossier va expirer + states: + brouillon: "" # not applicable, instructeur does not see brouillons + en_construction: Ce dossier est en attente de prise en charge. Vous pouvez toutefois entendre cette durée d'un mois en cliquant sur le bouton suivant. + termine: Le traitement de ce dossier est terminé, mais il va bientôt expirer. Cela signifie qu’il va bientôt être supprimé. Si vous souhaitez conserver une trace, vous pouvez le télécharger au format PDF. + button_delay_expiration: "Repousser sa suppression" diff --git a/config/locales/views/users/header/en.yml b/config/locales/views/users/header/en.yml new file mode 100644 index 000000000..b8e533c40 --- /dev/null +++ b/config/locales/views/users/header/en.yml @@ -0,0 +1,11 @@ +en: + users: + dossiers: + header: + banner: + title: Your file will expire + states: + brouillon: Your file is still in draft and will soon expire. So it will be deleted soon without being instructed. If you want to pursue your procedure you can submit it now. Otherwise you are able to delay its expiration by clicking on the underneath button. + en_construction: Your file is pending for instruction. The maximum delay is 6 months, but you can extend the duration by a month by clicking on the underneath button. + termine: Your file had been processed and will soon expire. So it will be deleted soon. If you want to keep it, you can dowload a PDF file of it. + button_delay_expiration: "Delay deletion" diff --git a/config/locales/views/users/header/fr.yml b/config/locales/views/users/header/fr.yml new file mode 100644 index 000000000..3749b98a9 --- /dev/null +++ b/config/locales/views/users/header/fr.yml @@ -0,0 +1,11 @@ +fr: + users: + dossiers: + header: + banner: + title: Votre dossier va expirer + states: + brouillon: Votre dossier est en brouillon, mais va bientôt expirer. Cela signifie qu’il va bientôt être supprimé sans avoir été déposé. Si vous souhaitez le conserver afin de poursuivre la démarche, vous pouvez le conserver un mois de plus en cliquant sur le bouton ci-dessous. + en_construction: Votre dossier est en attente de prise en charge par l'administration. Le delais de prise en charge maximale est de 6 mois. Vous pouvez toutefois entendre cette durée d'un mois en cliquant sur le bouton suivant. + termine: Le traitement de votre dossier est terminé, mais il va bientôt expirer. Cela signifie qu’il va bientôt être supprimé. Si vous souhaitez conserver une trace, vous pouvez le télécharger au format PDF. + button_delay_expiration: "Repousser sa suppression" diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index 7cdfd8304..874beb40a 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -719,8 +719,8 @@ describe Instructeur, type: :model do it { expect(subject['a_suivre']).to eq(0) } it { expect(subject['suivis']).to eq(0) } - it { expect(subject['traites']).to eq(2) } - it { expect(subject['tous']).to eq(2) } + it { expect(subject['traites']).to eq(1) } + it { expect(subject['tous']).to eq(1) } it { expect(subject['archives']).to eq(0) } it { expect(subject['expirant']).to eq(0) } end diff --git a/spec/views/instructeur/dossiers/_expiration_banner.html.haml_spec.rb b/spec/views/instructeur/dossiers/_expiration_banner.html.haml_spec.rb new file mode 100644 index 000000000..e1434fb5f --- /dev/null +++ b/spec/views/instructeur/dossiers/_expiration_banner.html.haml_spec.rb @@ -0,0 +1,66 @@ +describe 'instructeur/dossiers/expiration_banner.html.haml', type: :view do + include DossierHelper + let(:duree_conservation_dossiers_dans_ds) { 3 } + let(:dossier) do + create(:dossier, state, attributes.merge( + id: 1, + state: state, + procedure: create(:procedure, procedure_expires_when_termine_enabled: expiration_enabled, duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds) + )) + end + let(:i18n_key_state) { state } + subject do + render('instructeurs/dossiers/expiration_banner.html.haml', + dossier: dossier, + current_user: build(:user)) + end + + context 'with procedure having procedure_expires_when_termine_enabled not enabled' do + let(:expiration_enabled) { false } + let(:attributes) { { processed_at: 6.months.ago } } + let(:state) { :accepte } + + it 'render estimated expiration date' do + expect(subject).not_to have_selector('.expires_at') + end + end + + context 'with procedure having procedure_expires_when_termine_enabled enabled' do + let(:expiration_enabled) { true } + + context 'with dossier.en_construction?' do + let(:attributes) { { en_construction_at: 6.months.ago } } + let(:state) { :en_construction } + + it 'render estimated expiration date' do + expect(subject).to have_selector('.expires_at', + text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}", + date: safe_expiration_date(dossier), + duree_conservation_totale: duree_conservation_dossiers_dans_ds)) + end + end + + context 'with dossier.en_instruction?' do + let(:state) { :en_instruction } + let(:attributes) { {} } + + it 'render estimated expiration date' do + expect(subject).to have_selector('p.expires_at_en_instruction', + text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}")) + end + end + + context 'with dossier.en_processed_at?' do + let(:state) { :accepte } + let(:attributes) { {} } + + it 'render estimated expiration date' do + allow(dossier).to receive(:processed_at).and_return(6.months.ago) + expect(subject).to have_selector('.expires_at', + text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}", + date: safe_expiration_date(dossier), + duree_conservation_totale: duree_conservation_dossiers_dans_ds)) + end + end + end +end diff --git a/spec/views/instructeur/procedures/_header.html.haml_spec.rb b/spec/views/instructeur/procedures/_header.html.haml_spec.rb index a9da674d0..8e1734994 100644 --- a/spec/views/instructeur/procedures/_header.html.haml_spec.rb +++ b/spec/views/instructeur/procedures/_header.html.haml_spec.rb @@ -1,5 +1,7 @@ describe 'instructeurs/procedures/_header.html.haml', type: :view do - let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled)} + let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled) } + + before { allow(view).to receive(:current_instructeur).and_return(create(:instructeur)) } subject do render('instructeurs/procedures/header.html.haml', @@ -12,8 +14,7 @@ describe 'instructeurs/procedures/_header.html.haml', type: :view do archives_count: 0, expirant_count: 0, has_en_cours_notifications: false, - has_termine_notifications: false, - current_instructeur: build_stubbed(:instructeur)) + has_termine_notifications: false) end context 'when procedure_expires_when_termine_enabled is true' do diff --git a/spec/views/instructeur/procedures/_list.html.haml_spec.rb b/spec/views/instructeur/procedures/_list.html.haml_spec.rb index 513013386..7de854f9a 100644 --- a/spec/views/instructeur/procedures/_list.html.haml_spec.rb +++ b/spec/views/instructeur/procedures/_list.html.haml_spec.rb @@ -1,5 +1,5 @@ describe 'instructeurs/procedures/_list.html.haml', type: :view do - let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled)} + let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled) } subject do render('instructeurs/procedures/list.html.haml', diff --git a/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb b/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb index 30d3bef90..8bf0c3d51 100644 --- a/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb +++ b/spec/views/users/dossiers/_expiration_banner.html.haml_spec.rb @@ -1,11 +1,12 @@ describe 'users/dossiers/expiration_banner.html.haml', type: :view do include DossierHelper - + let(:duree_conservation_dossiers_dans_ds) { 3 } let(:dossier) do create(:dossier, state, attributes.merge( id: 1, state: state, - procedure: create(:procedure, procedure_expires_when_termine_enabled: expiration_enabled) + conservation_extension: 1, + procedure: create(:procedure, procedure_expires_when_termine_enabled: expiration_enabled, duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds) )) end let(:i18n_key_state) { state } @@ -35,7 +36,8 @@ describe 'users/dossiers/expiration_banner.html.haml', type: :view do it 'render estimated expiration date' do expect(subject).to have_selector('.expires_at', text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}", - date: safe_expiration_date(dossier))) + date: safe_expiration_date(dossier), + duree_conservation_totale: duree_conservation_dossiers_dans_ds)) end end @@ -46,7 +48,8 @@ describe 'users/dossiers/expiration_banner.html.haml', type: :view do it 'render estimated expiration date' do expect(subject).to have_selector('.expires_at', text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}", - date: safe_expiration_date(dossier))) + date: safe_expiration_date(dossier), + duree_conservation_totale: duree_conservation_dossiers_dans_ds)) end end @@ -68,7 +71,8 @@ describe 'users/dossiers/expiration_banner.html.haml', type: :view do allow(dossier).to receive(:processed_at).and_return(6.months.ago) expect(subject).to have_selector('.expires_at', text: I18n.t("shared.dossiers.header.expires_at.#{i18n_key_state}", - date: safe_expiration_date(dossier))) + date: safe_expiration_date(dossier), + duree_conservation_totale: duree_conservation_dossiers_dans_ds)) end end end From 081d5094a9c2b4f67b9ffbd641c86922df9f541f Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 3 Dec 2021 16:09:51 +0100 Subject: [PATCH 15/19] feat(instructeurs/procedure/dossiers#extend_conservation): add extends duree conservation in action button list, also rewire this action for user [extend by procedure.duree_conservation_dans_ds by default] but force 1.month for instructeur. add new icon for standby based on https://en.wikipedia.org/wiki/Power_symbol --- app/assets/images/icons/standby.svg | 1 + app/assets/stylesheets/icons.scss | 4 +++ .../instructeurs/dossiers_controller.rb | 6 ++++ app/controllers/users/dossiers_controller.rb | 6 ++-- app/models/dossier.rb | 1 + .../dossiers/_expiration_banner.html.haml | 9 ++++-- .../dossiers/_header_actions.html.haml | 3 +- .../procedures/_dossier_actions.html.haml | 7 ++++- .../instructeurs/procedures/show.html.haml | 11 +++---- app/views/recherche/index.html.haml | 3 +- .../dossiers/_expiration_banner.html.haml | 4 ++- config/locales/fr.yml | 3 +- config/locales/views/instructeurs/fr.yml | 2 ++ .../locales/views/instructeurs/header/en.yml | 3 +- .../locales/views/instructeurs/header/fr.yml | 3 +- config/locales/views/users/header/en.yml | 2 +- config/locales/views/users/header/fr.yml | 2 +- config/routes.rb | 2 +- .../instructeurs/dossiers_controller_spec.rb | 19 ++++++++++++ .../users/dossiers_controller_spec.rb | 29 +++++++++++++++++++ spec/system/users/brouillon_spec.rb | 13 ++++----- 21 files changed, 106 insertions(+), 27 deletions(-) create mode 100644 app/assets/images/icons/standby.svg diff --git a/app/assets/images/icons/standby.svg b/app/assets/images/icons/standby.svg new file mode 100644 index 000000000..d859108ea --- /dev/null +++ b/app/assets/images/icons/standby.svg @@ -0,0 +1 @@ + diff --git a/app/assets/stylesheets/icons.scss b/app/assets/stylesheets/icons.scss index a05037802..734799e9b 100644 --- a/app/assets/stylesheets/icons.scss +++ b/app/assets/stylesheets/icons.scss @@ -19,6 +19,10 @@ background-image: image-url("icons/unfollow-folder.svg"); } + &.standby { + background-image: image-url("icons/standby.svg"); + } + &.archive { background-image: image-url("icons/archive.svg"); } diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index 2d35d2856..1d56d8acc 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -19,6 +19,12 @@ module Instructeurs end end + def extend_conservation + dossier.update(conservation_extension: dossier.conservation_extension + 1.month) + flash[:notice] = t('views.instructeurs.dossiers.archived_dossier') + redirect_back(fallback_location: instructeur_dossier_path(@dossier.procedure, @dossier)) + end + def geo_data send_data dossier.to_feature_collection.to_json, type: 'application/json', diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index b591c3700..83a455c39 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -168,9 +168,9 @@ module Users end def extend_conservation - dossier.update(conservation_extension: dossier.conservation_extension + 1.month) - flash[:notice] = t('.archived_dossier') - redirect_to dossier_path(@dossier) + dossier.update(conservation_extension: dossier.conservation_extension + dossier.procedure.duree_conservation_dossiers_dans_ds.months) + flash[:notice] = t('views.users.dossiers.archived_dossier', duree_conservation_dossiers_dans_ds: dossier.procedure.duree_conservation_dossiers_dans_ds) + redirect_back(fallback_location: dossier_path(@dossier)) end def modifier diff --git a/app/models/dossier.rb b/app/models/dossier.rb index c40d6be2e..9dbf715e3 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -569,6 +569,7 @@ class Dossier < ApplicationRecord end def close_to_expiration? + return false if en_instruction? approximative_expiration_date < Time.zone.now end diff --git a/app/views/instructeurs/dossiers/_expiration_banner.html.haml b/app/views/instructeurs/dossiers/_expiration_banner.html.haml index 0dee1a5ea..e1b4329e5 100644 --- a/app/views/instructeurs/dossiers/_expiration_banner.html.haml +++ b/app/views/instructeurs/dossiers/_expiration_banner.html.haml @@ -2,7 +2,10 @@ - if dossier.expirable? %p.expires_at.mb-2 - %small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) + %small + = t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) + - if dossier.conservation_extension.positive? + = t('instructeurs.dossiers.header.banner.expiration_date_extended') -# big banner warning - if dossier.close_to_expiration? .card.warning.mb-3 @@ -17,7 +20,9 @@ - if dossier.expiration_can_be_extended? %br - = button_to t('instructeurs.dossiers.header.banner.button_delay_expiration'), users_dossier_repousser_expiration_path(dossier), class: 'button secondary mt-2' + = button_to repousser_expiration_instructeur_dossier_path(dossier.procedure, dossier), class: 'button mt-2', id: 'test-instructeur-repousser-expiration' do + %span.icon.standby + = t('instructeurs.dossiers.header.banner.button_delay_expiration') - else diff --git a/app/views/instructeurs/dossiers/_header_actions.html.haml b/app/views/instructeurs/dossiers/_header_actions.html.haml index ca50a1164..47f7b4893 100644 --- a/app/views/instructeurs/dossiers/_header_actions.html.haml +++ b/app/views/instructeurs/dossiers/_header_actions.html.haml @@ -27,7 +27,8 @@ dossier_id: dossier.id, state: dossier.state, archived: dossier.archived, - dossier_is_followed: current_instructeur&.follow?(dossier) } + dossier_is_followed: current_instructeur&.follow?(dossier), + close_to_expiration: dossier.close_to_expiration? } .state-button diff --git a/app/views/instructeurs/procedures/_dossier_actions.html.haml b/app/views/instructeurs/procedures/_dossier_actions.html.haml index 710330bcb..bc1f994c5 100644 --- a/app/views/instructeurs/procedures/_dossier_actions.html.haml +++ b/app/views/instructeurs/procedures/_dossier_actions.html.haml @@ -1,9 +1,14 @@ -- if Dossier::TERMINE.include?(state) +- if close_to_expiration || Dossier::TERMINE.include?(state) .dropdown.user-dossier-actions %button.button.dropdown-button{ 'aria-expanded' => 'false', 'aria-controls' => 'actions-menu' } Actions #actions-menu.dropdown-content.fade-in-down %ul.dropdown-items + - if close_to_expiration + %li + = link_to repousser_expiration_instructeur_dossier_path(procedure_id, dossier_id), method: :post do + %span.icon.standby + .dropdown-description= t('instructeurs.dossiers.header.banner.button_delay_expiration') - if archived %li = link_to unarchive_instructeur_dossier_path(procedure_id, dossier_id), method: :patch do diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml index 41207a162..e4a19555c 100644 --- a/app/views/instructeurs/procedures/show.html.haml +++ b/app/views/instructeurs/procedures/show.html.haml @@ -123,11 +123,12 @@ %a.cell-link{ href: path }= status_badge(p.state) %td.action-col.follow-col= render partial: 'dossier_actions', - locals: { procedure_id: @procedure.id, - dossier_id: p.dossier_id, - state: p.state, - archived: p.archived, - dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id) } + locals: { procedure_id: @procedure.id, + dossier_id: p.dossier_id, + state: p.state, + archived: p.archived, + dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id), + close_to_expiration: @statut == 'expirant' } = pagination - else diff --git a/app/views/recherche/index.html.haml b/app/views/recherche/index.html.haml index 7bb5c6b53..90ebb65cc 100644 --- a/app/views/recherche/index.html.haml +++ b/app/views/recherche/index.html.haml @@ -81,7 +81,8 @@ dossier_id: p.dossier_id, state: p.state, archived: p.archived, - dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id) } + dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id), + close_to_expiration: nil } - else %td diff --git a/app/views/users/dossiers/_expiration_banner.html.haml b/app/views/users/dossiers/_expiration_banner.html.haml index ab04fea8f..d2a6e3cdf 100644 --- a/app/views/users/dossiers/_expiration_banner.html.haml +++ b/app/views/users/dossiers/_expiration_banner.html.haml @@ -16,7 +16,9 @@ - if dossier.expiration_can_be_extended? %br - = button_to t('users.dossiers.header.banner.button_delay_expiration'), users_dossier_repousser_expiration_path(dossier), class: 'button secondary mt-2' + = button_to users_dossier_repousser_expiration_path(dossier), class: 'button mt-2', id: 'test-user-repousser-expiration' do + %span.icon.standby + = t('users.dossiers.header.banner.button_delay_expiration', duree_conservation_dossiers_dans_ds: dossier.procedure.duree_conservation_dossiers_dans_ds) - else diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 81afc6b1d..b4af28f4b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -136,6 +136,7 @@ fr: introduction_file_explaination: "Fichier joint à la demande d’avis" users: dossiers: + archived_dossier: "Votre dossier sera conservé %{duree_conservation_dossiers_dans_ds} mois supplémentaire" autosave: autosave_draft: Votre brouillon est automatiquement enregistré. more_infos: En savoir plus @@ -390,7 +391,7 @@ fr: test_procedure: "Ce dossier est déposé sur une démarche en test. Toute modification de la démarche par l’administrateur (ajout d'un champ, publication de la démarche...) entraînera sa suppression." no_access: "Vous n’avez pas accès à ce dossier" no_longer_editable: "Votre dossier ne peut plus être modifié" - archived_dossier: "Votre dossier sera conservé %{duree_conservation_dossiers_dans_ds} mois supplémentaire" + create_commentaire: message_send: "Votre message a bien été envoyé à l’instructeur en charge de votre dossier." ask_deletion: diff --git a/config/locales/views/instructeurs/fr.yml b/config/locales/views/instructeurs/fr.yml index 464fbb855..cc8c539ff 100644 --- a/config/locales/views/instructeurs/fr.yml +++ b/config/locales/views/instructeurs/fr.yml @@ -18,6 +18,8 @@ fr: archive_pending_html: Archive en cours de création
(demandée il y a %{created_period}) archive_ready_html: Télécharger l’archive
(demandée il y a %{generated_period}) dossiers: + extend_conservation: + archived_dossier: "Le dossier sera conservé 1 mois supplémentaire" decisions_rendues_block: without_email: en_construction: Le %{processed_at} ce dossier a été passé en construction diff --git a/config/locales/views/instructeurs/header/en.yml b/config/locales/views/instructeurs/header/en.yml index 44ee0126a..3eeebdbf7 100644 --- a/config/locales/views/instructeurs/header/en.yml +++ b/config/locales/views/instructeurs/header/en.yml @@ -3,9 +3,10 @@ en: dossiers: header: banner: + expiration_date_extended: " – la date de conservation a déjà été etendue" title: This file will expire states: brouillon: "" # not applicable, instructeur does not see brouillons en_construction: This file is pending for instruction. The maximum delay is 6 months, you can extend the duration by a month by clicking on the underneath button. termine: This file had been processed and will soon expire. So it will be deleted soon. If you want to keep it, you can dowload a PDF file of it. - button_delay_expiration: "Delay deletion" + button_delay_expiration: "Keep for one more month" diff --git a/config/locales/views/instructeurs/header/fr.yml b/config/locales/views/instructeurs/header/fr.yml index 2248ed793..ca41a5f37 100644 --- a/config/locales/views/instructeurs/header/fr.yml +++ b/config/locales/views/instructeurs/header/fr.yml @@ -3,9 +3,10 @@ fr: dossiers: header: banner: + expiration_date_extended: " – la date de conservation a déjà été etendue" title: Ce dossier va expirer states: brouillon: "" # not applicable, instructeur does not see brouillons en_construction: Ce dossier est en attente de prise en charge. Vous pouvez toutefois entendre cette durée d'un mois en cliquant sur le bouton suivant. termine: Le traitement de ce dossier est terminé, mais il va bientôt expirer. Cela signifie qu’il va bientôt être supprimé. Si vous souhaitez conserver une trace, vous pouvez le télécharger au format PDF. - button_delay_expiration: "Repousser sa suppression" + button_delay_expiration: "Conserver un mois de plus" diff --git a/config/locales/views/users/header/en.yml b/config/locales/views/users/header/en.yml index b8e533c40..37a23c3ab 100644 --- a/config/locales/views/users/header/en.yml +++ b/config/locales/views/users/header/en.yml @@ -8,4 +8,4 @@ en: brouillon: Your file is still in draft and will soon expire. So it will be deleted soon without being instructed. If you want to pursue your procedure you can submit it now. Otherwise you are able to delay its expiration by clicking on the underneath button. en_construction: Your file is pending for instruction. The maximum delay is 6 months, but you can extend the duration by a month by clicking on the underneath button. termine: Your file had been processed and will soon expire. So it will be deleted soon. If you want to keep it, you can dowload a PDF file of it. - button_delay_expiration: "Delay deletion" + button_delay_expiration: "Keep for %{duree_conservation_dossiers_dans_ds} more months" diff --git a/config/locales/views/users/header/fr.yml b/config/locales/views/users/header/fr.yml index 3749b98a9..5d2af1fad 100644 --- a/config/locales/views/users/header/fr.yml +++ b/config/locales/views/users/header/fr.yml @@ -8,4 +8,4 @@ fr: brouillon: Votre dossier est en brouillon, mais va bientôt expirer. Cela signifie qu’il va bientôt être supprimé sans avoir été déposé. Si vous souhaitez le conserver afin de poursuivre la démarche, vous pouvez le conserver un mois de plus en cliquant sur le bouton ci-dessous. en_construction: Votre dossier est en attente de prise en charge par l'administration. Le delais de prise en charge maximale est de 6 mois. Vous pouvez toutefois entendre cette durée d'un mois en cliquant sur le bouton suivant. termine: Le traitement de votre dossier est terminé, mais il va bientôt expirer. Cela signifie qu’il va bientôt être supprimé. Si vous souhaitez conserver une trace, vous pouvez le télécharger au format PDF. - button_delay_expiration: "Repousser sa suppression" + button_delay_expiration: "Conserver %{duree_conservation_dossiers_dans_ds} mois supplémentaires " diff --git a/config/routes.rb b/config/routes.rb index c8c54d808..f9b7d055f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -361,7 +361,7 @@ Rails.application.routes.draw do resources :dossiers, only: [:show], param: :dossier_id do member do resources :commentaires, only: [:destroy] - + post '/repousser-expiration' => 'dossiers#extend_conservation' get 'attestation' get 'geo_data' get 'apercu_attestation' diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index c19ef620f..169fc19be 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -804,4 +804,23 @@ describe Instructeurs::DossiersController, type: :controller do end end end + + describe '#extend_conservation' do + subject { post :extend_conservation, params: { procedure_id: procedure.id, dossier_id: dossier.id } } + context 'when user logged in' do + it 'works' do + expect(subject).to redirect_to(instructeur_dossier_path(procedure, dossier)) + end + + it 'extends conservation_extension by 1 month' do + subject + expect(dossier.reload.conservation_extension).to eq(1.month) + end + + it 'flashed notice success' do + subject + expect(flash[:notice]).to eq(I18n.t('views.instructeurs.dossiers.archived_dossier')) + end + end + end end diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 9b7517f44..adf3f7ab8 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -1161,4 +1161,33 @@ describe Users::DossiersController, type: :controller do expect(response).to have_http_status(:ok) end end + + describe '#extend_conservation' do + let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 3) } + let(:dossier) { create(:dossier, procedure: procedure, user: user) } + subject { post :extend_conservation, params: { dossier_id: dossier.id } } + context 'when user logged in' do + before { sign_in(user) } + it 'works' do + expect(subject).to redirect_to(dossier_path(dossier)) + end + + it 'extends conservation_extension by duree_conservation_dossiers_dans_ds' do + subject + expect(dossier.reload.conservation_extension).to eq(procedure.duree_conservation_dossiers_dans_ds.months) + end + + it 'flashed notice success' do + subject + expect(flash[:notice]).to eq(I18n.t('views.users.dossiers.archived_dossier', duree_conservation_dossiers_dans_ds: procedure.duree_conservation_dossiers_dans_ds)) + end + end + + context 'when not logged in' do + it 'fails' do + subject + expect { expect(response).to redirect_to(new_user_session_path) } + end + end + end end diff --git a/spec/system/users/brouillon_spec.rb b/spec/system/users/brouillon_spec.rb index e0d6402f4..aa07cc222 100644 --- a/spec/system/users/brouillon_spec.rb +++ b/spec/system/users/brouillon_spec.rb @@ -166,7 +166,7 @@ describe 'The user' do end scenario 'extends dossier experation date more than one time, ', js: true do - Flipper.enable(:procedure_process_expired_dossiers_termine) + simple_procedure.update(procedure_expires_when_termine_enabled: true) allow(simple_procedure).to receive(:feature_enabled?).with(:procedure_process_expired_dossiers_termine).and_return(true) user_old_dossier = create(:dossier, procedure: simple_procedure, @@ -176,15 +176,14 @@ describe 'The user' do visit brouillon_dossier_path(user_old_dossier) expect(page).to have_css('.card-title', text: 'Votre dossier va expirer', visible: true) - click_on "Repousser sa suppression" - expect(page).not_to have_button("Repousser sa suppression") + find('#test-user-repousser-expiration').click + expect(page).not_to have_selector('#test-user-repousser-expiration') - Timecop.freeze(1.month.from_now) do + Timecop.freeze(simple_procedure.duree_conservation_dossiers_dans_ds.month.from_now) do visit brouillon_dossier_path(user_old_dossier) - expect(page).to have_css('.card-title', text: 'Votre dossier va expirer', visible: true) - click_on "Repousser sa suppression" - expect(page).not_to have_button("Repousser sa suppression") + find('#test-user-repousser-expiration').click + expect(page).not_to have_selector('#test-user-repousser-expiration') end end From 2778b42f1aefe824de5e5e8fccef08cf4644bd4d Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 3 Dec 2021 16:21:41 +0100 Subject: [PATCH 16/19] feat(instructeurs/procedures#show): re-align tabs at the start of the container. re-align demander cell content verticaly --- .../instructeurs/procedures_controller.rb | 4 +-- .../instructeurs/procedures/_header.html.haml | 34 ------------------- .../instructeurs/procedures/_tabs.html.haml | 34 +++++++++++++++++++ .../instructeurs/procedures/show.html.haml | 10 +++--- .../users/dossiers/_dossiers_list.html.haml | 4 +-- ...l.haml_spec.rb => _tabs.html.haml_spec.rb} | 4 +-- 6 files changed, 46 insertions(+), 44 deletions(-) create mode 100644 app/views/instructeurs/procedures/_tabs.html.haml rename spec/views/instructeur/procedures/{_header.html.haml_spec.rb => _tabs.html.haml_spec.rb} (90%) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index e9954280f..3cca930e6 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -15,9 +15,9 @@ module Instructeurs dossiers = current_instructeur.dossiers.joins(:groupe_instructeur) @dossiers_count_per_procedure = dossiers.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count - @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count # why not reorder(nil) + @dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count @dossiers_termines_count_per_procedure = dossiers.termine.group('groupe_instructeurs.procedure_id').reorder(nil).count - @dossiers_expirant_count_per_procedure = dossiers.termine_or_en_construction_close_to_expiration.group('groupe_instructeurs.procedure_id').count # why not reorder(nil) + @dossiers_expirant_count_per_procedure = dossiers.termine_or_en_construction_close_to_expiration.group('groupe_instructeurs.procedure_id').count groupe_ids = current_instructeur.groupe_instructeurs.pluck(:id) @followed_dossiers_count_per_procedure = current_instructeur diff --git a/app/views/instructeurs/procedures/_header.html.haml b/app/views/instructeurs/procedures/_header.html.haml index 66be03776..58598bac1 100644 --- a/app/views/instructeurs/procedures/_header.html.haml +++ b/app/views/instructeurs/procedures/_header.html.haml @@ -17,37 +17,3 @@ | = link_to 'contacter les usagers (brouillon)', email_usagers_instructeur_procedure_path(procedure), class: 'header-link' - %ul.tabs - = tab_item('à suivre', - instructeur_procedure_path(procedure, statut: 'a-suivre'), - active: statut == 'a-suivre', - badge: number_with_html_delimiter(a_suivre_count)) - - = tab_item(t('pluralize.followed', count: suivis_count), - instructeur_procedure_path(procedure, statut: 'suivis'), - active: statut == 'suivis', - badge: number_with_html_delimiter(suivis_count), - notification: has_en_cours_notifications) - - = tab_item(t('pluralize.processed', count: traites_count), - instructeur_procedure_path(procedure, statut: 'traites'), - active: statut == 'traites', - badge: number_with_html_delimiter(traites_count), - notification: has_termine_notifications) - - = tab_item('au total', - instructeur_procedure_path(procedure, statut: 'tous'), - active: statut == 'tous', - badge: number_with_html_delimiter(tous_count)) - - - if procedure.procedure_expires_when_termine_enabled - = tab_item(t('pluralize.dossiers_close_to_expiration', count: expirant_count), - instructeur_procedure_path(procedure, statut: 'expirant'), - active: statut == 'expirant', - badge: number_with_html_delimiter(expirant_count)) - - = tab_item(t('pluralize.archived', count: archives_count), - instructeur_procedure_path(procedure, statut: 'archives'), - active: statut == 'archives', - badge: number_with_html_delimiter(archives_count)) - diff --git a/app/views/instructeurs/procedures/_tabs.html.haml b/app/views/instructeurs/procedures/_tabs.html.haml new file mode 100644 index 000000000..7de8176b5 --- /dev/null +++ b/app/views/instructeurs/procedures/_tabs.html.haml @@ -0,0 +1,34 @@ +%ul.tabs.mt-3 + = tab_item('à suivre', + instructeur_procedure_path(procedure, statut: 'a-suivre'), + active: statut == 'a-suivre', + badge: number_with_html_delimiter(a_suivre_count)) + + = tab_item(t('pluralize.followed', count: suivis_count), + instructeur_procedure_path(procedure, statut: 'suivis'), + active: statut == 'suivis', + badge: number_with_html_delimiter(suivis_count), + notification: has_en_cours_notifications) + + = tab_item(t('pluralize.processed', count: traites_count), + instructeur_procedure_path(procedure, statut: 'traites'), + active: statut == 'traites', + badge: number_with_html_delimiter(traites_count), + notification: has_termine_notifications) + + = tab_item('au total', + instructeur_procedure_path(procedure, statut: 'tous'), + active: statut == 'tous', + badge: number_with_html_delimiter(tous_count)) + + - if procedure.procedure_expires_when_termine_enabled + = tab_item(t('pluralize.dossiers_close_to_expiration', count: expirant_count), + instructeur_procedure_path(procedure, statut: 'expirant'), + active: statut == 'expirant', + badge: number_with_html_delimiter(expirant_count)) + + = tab_item(t('pluralize.archived', count: archives_count), + instructeur_procedure_path(procedure, statut: 'archives'), + active: statut == 'archives', + badge: number_with_html_delimiter(archives_count)) + diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml index e4a19555c..9984426ea 100644 --- a/app/views/instructeurs/procedures/show.html.haml +++ b/app/views/instructeurs/procedures/show.html.haml @@ -7,7 +7,11 @@ .procedure-logo{ style: "background-image: url(#{@procedure.logo_url})", role: 'img', 'aria-label': "logo de la démarche #{@procedure.libelle}" } - = render partial: 'header', locals: { procedure: @procedure, + = render partial: 'header', locals: { procedure: @procedure, statut: @statut } + + .procedure-actions + = render partial: "download_dossiers", locals: { procedure: @procedure, exports: @exports, dossier_count: @tous_count + @archives_count } + .container.flex= render partial: "tabs", locals: { procedure: @procedure, statut: @statut, a_suivre_count: @a_suivre_count, suivis_count: @suivis_count, @@ -18,9 +22,6 @@ has_en_cours_notifications: @has_en_cours_notifications, has_termine_notifications: @has_termine_notifications } - .procedure-actions - = render partial: "download_dossiers", locals: { procedure: @procedure, exports: @exports, dossier_count: @tous_count + @archives_count } - .container - if @statut == 'a-suivre' %p.explication-onglet Aucun instructeur n’est affecté au suivi de ces dossiers. Soyez le premier ! @@ -46,6 +47,7 @@ - if @statut == 'expirant' %p.explication-onglet Les dossiers n'expireront pas avant la période de conservation des données. + - if @filtered_sorted_paginated_ids.present? || @current_filters.count > 0 - pagination = paginate @filtered_sorted_paginated_ids = pagination diff --git a/app/views/users/dossiers/_dossiers_list.html.haml b/app/views/users/dossiers/_dossiers_list.html.haml index 1b21c09ad..3d043ac56 100644 --- a/app/views/users/dossiers/_dossiers_list.html.haml +++ b/app/views/users/dossiers/_dossiers_list.html.haml @@ -20,8 +20,8 @@ = link_to(url_for_dossier(dossier), class: 'cell-link') do = procedure_libelle(dossier.procedure) - if dossiers.present? - %td.cell-link - = demandeur_dossier(dossier) + %td + %span.cell-link= demandeur_dossier(dossier) %td.status-col = status_badge(dossier.state) %td.updated-at-col.cell-link diff --git a/spec/views/instructeur/procedures/_header.html.haml_spec.rb b/spec/views/instructeur/procedures/_tabs.html.haml_spec.rb similarity index 90% rename from spec/views/instructeur/procedures/_header.html.haml_spec.rb rename to spec/views/instructeur/procedures/_tabs.html.haml_spec.rb index 8e1734994..e69a66a37 100644 --- a/spec/views/instructeur/procedures/_header.html.haml_spec.rb +++ b/spec/views/instructeur/procedures/_tabs.html.haml_spec.rb @@ -1,10 +1,10 @@ -describe 'instructeurs/procedures/_header.html.haml', type: :view do +describe 'instructeurs/procedures/_tabs.html.haml', type: :view do let(:procedure) { create(:procedure, id: 1, procedure_expires_when_termine_enabled: expiration_enabled) } before { allow(view).to receive(:current_instructeur).and_return(create(:instructeur)) } subject do - render('instructeurs/procedures/header.html.haml', + render('instructeurs/procedures/tabs.html.haml', procedure: procedure, statut: 'tous', a_suivre_count: 0, From a9413f9b127f2312b8141d07d93b578434c195e8 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 6 Dec 2021 06:12:40 +0100 Subject: [PATCH 17/19] feat(manager): add procedure_expires_when_termine_enabled to administrate --- app/dashboards/procedure_dashboard.rb | 10 +++++++--- config/locales/views/instructeurs/header/en.yml | 2 +- config/routes.rb | 2 +- spec/models/instructeur_spec.rb | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/dashboards/procedure_dashboard.rb b/app/dashboards/procedure_dashboard.rb index aaf0717db..992ea66b4 100644 --- a/app/dashboards/procedure_dashboard.rb +++ b/app/dashboards/procedure_dashboard.rb @@ -34,7 +34,8 @@ class ProcedureDashboard < Administrate::BaseDashboard closed_mail_template: MailTemplateField, refused_mail_template: MailTemplateField, without_continuation_mail_template: MailTemplateField, - attestation_template: AttestationTemplateField + attestation_template: AttestationTemplateField, + procedure_expires_when_termine_enabled: Field::Boolean }.freeze # COLLECTION_ATTRIBUTES @@ -79,13 +80,16 @@ class ProcedureDashboard < Administrate::BaseDashboard :closed_mail_template, :refused_mail_template, :without_continuation_mail_template, - :attestation_template + :attestation_template, + :procedure_expires_when_termine_enabled ].freeze # FORM_ATTRIBUTES # an array of attributes that will be displayed # on the model's form (`new` and `edit`) pages. - FORM_ATTRIBUTES = [].freeze + FORM_ATTRIBUTES = [ + :procedure_expires_when_termine_enabled + ].freeze # Overwrite this method to customize how procedures are displayed # across all pages of the admin dashboard. diff --git a/config/locales/views/instructeurs/header/en.yml b/config/locales/views/instructeurs/header/en.yml index 3eeebdbf7..bf30db1e0 100644 --- a/config/locales/views/instructeurs/header/en.yml +++ b/config/locales/views/instructeurs/header/en.yml @@ -3,7 +3,7 @@ en: dossiers: header: banner: - expiration_date_extended: " – la date de conservation a déjà été etendue" + expiration_date_extended: " – the expiration date had already been extended" title: This file will expire states: brouillon: "" # not applicable, instructeur does not see brouillons diff --git a/config/routes.rb b/config/routes.rb index f9b7d055f..27bd36ca1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,7 +10,7 @@ Rails.application.routes.draw do # namespace :manager do - resources :procedures, only: [:index, :show] do + resources :procedures, only: [:index, :show, :edit, :update] do post 'whitelist', on: :member post 'draft', on: :member post 'discard', on: :member diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index 874beb40a..7cdfd8304 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -719,8 +719,8 @@ describe Instructeur, type: :model do it { expect(subject['a_suivre']).to eq(0) } it { expect(subject['suivis']).to eq(0) } - it { expect(subject['traites']).to eq(1) } - it { expect(subject['tous']).to eq(1) } + it { expect(subject['traites']).to eq(2) } + it { expect(subject['tous']).to eq(2) } it { expect(subject['archives']).to eq(0) } it { expect(subject['expirant']).to eq(0) } end From 45a74ee99957f18eebd4f36c1967f54c99e6cea2 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 6 Dec 2021 13:09:46 +0100 Subject: [PATCH 18/19] clean(routes): based on review --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 27bd36ca1..2a2dc2503 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -361,7 +361,7 @@ Rails.application.routes.draw do resources :dossiers, only: [:show], param: :dossier_id do member do resources :commentaires, only: [:destroy] - post '/repousser-expiration' => 'dossiers#extend_conservation' + post 'repousser-expiration' => 'dossiers#extend_conservation' get 'attestation' get 'geo_data' get 'apercu_attestation' From bb9b750ce9cfb081fa709a55ae0a6e1de601469b Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 6 Dec 2021 13:11:46 +0100 Subject: [PATCH 19/19] merge(main): fix conflict --- db/schema.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 125f43af3..2ea7addb4 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_11_27_143736) do +ActiveRecord::Schema.define(version: 2021_12_01_135804) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -554,14 +554,6 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.index ["user_id"], name: "index_merge_logs_on_user_id" end - create_table "zones", force: :cascade do |t| - t.string "acronym", null: false - t.string "label" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - t.index ["acronym"], name: "index_zones_on_acronym", unique: true - end - create_table "module_api_cartos", id: :serial, force: :cascade do |t| t.integer "procedure_id" t.boolean "use_api_carto", default: false @@ -646,9 +638,9 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.text "api_particulier_scopes", default: [], array: true t.jsonb "api_particulier_sources", default: {} t.boolean "instructeurs_self_management_enabled" - t.bigint "zone_id" t.boolean "routing_enabled" t.boolean "procedure_expires_when_termine_enabled", default: false + t.bigint "zone_id" t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state" t.index ["draft_revision_id"], name: "index_procedures_on_draft_revision_id" @@ -836,6 +828,14 @@ ActiveRecord::Schema.define(version: 2021_11_27_143736) do t.index ["procedure_id"], name: "index_without_continuation_mails_on_procedure_id" end + create_table "zones", force: :cascade do |t| + t.string "acronym", null: false + t.string "label" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["acronym"], name: "index_zones_on_acronym", unique: true + end + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "archives_groupe_instructeurs", "archives" add_foreign_key "archives_groupe_instructeurs", "groupe_instructeurs"