From 3f7693ae1311971fefbc350622e5893409f1b0cd Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 21:51:09 +0200 Subject: [PATCH 01/19] style remove blank line --- app/lib/active_storage/downloadable_file.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 8c3855ad4..413662fc3 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -1,4 +1,3 @@ - class ActiveStorage::DownloadableFile def self.create_list_from_dossier(dossier, for_expert = false) dossier_export = PiecesJustificativesService.generate_dossier_export(dossier) From cf79e340ef3f7de76cf1f484f810a142dda4754d Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 22:05:18 +0200 Subject: [PATCH 02/19] remove unused method --- app/lib/active_storage/downloadable_file.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 413662fc3..15895ccc6 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -46,8 +46,4 @@ class ActiveStorage::DownloadableFile 'pieces_justificatives/' end end - - def using_local_backend? - [:local, :local_test, :test].include?(Rails.application.config.active_storage.service) - end end From 51b71aaa01b13781056f5bbd988956953fe4be5d Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 5 Apr 2022 14:20:59 +0200 Subject: [PATCH 03/19] always call create_list_from_dossiers --- app/controllers/experts/avis_controller.rb | 2 +- app/controllers/instructeurs/dossiers_controller.rb | 2 +- app/lib/active_storage/downloadable_file.rb | 4 ++-- spec/lib/active_storage/downloadable_file_spec.rb | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/experts/avis_controller.rb b/app/controllers/experts/avis_controller.rb index 6523fcd2c..a298d4485 100644 --- a/app/controllers/experts/avis_controller.rb +++ b/app/controllers/experts/avis_controller.rb @@ -139,7 +139,7 @@ module Experts end def telecharger_pjs - files = ActiveStorage::DownloadableFile.create_list_from_dossier(@dossier, true) + files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: @dossier.id), true) zipline(files, "dossier-#{@dossier.id}.zip") end diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index 8612359ea..e941f50e3 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -218,7 +218,7 @@ module Instructeurs end def telecharger_pjs - files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier) + files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id)) zipline(files, "dossier-#{dossier.id}.zip") end diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 15895ccc6..85a3c586f 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -10,9 +10,9 @@ class ActiveStorage::DownloadableFile end end - def self.create_list_from_dossiers(dossiers) + def self.create_list_from_dossiers(dossiers, for_expert = false) dossiers.flat_map do |dossier| - create_list_from_dossier(dossier) + create_list_from_dossier(dossier, for_expert) end end diff --git a/spec/lib/active_storage/downloadable_file_spec.rb b/spec/lib/active_storage/downloadable_file_spec.rb index 755a0643c..011614265 100644 --- a/spec/lib/active_storage/downloadable_file_spec.rb +++ b/spec/lib/active_storage/downloadable_file_spec.rb @@ -1,9 +1,9 @@ describe ActiveStorage::DownloadableFile do let(:dossier) { create(:dossier, :en_construction) } - subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossier(dossier) } + subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id)) } - describe 'create_list_from_dossier' do + describe 'create_list_from_dossiers' do context 'when no piece_justificative is present' do it { expect(list.length).to eq 1 } it { expect(list.first[0].name).to eq "pdf_export_for_instructeur" } @@ -60,7 +60,7 @@ describe ActiveStorage::DownloadableFile do let(:champ) { dossier.champs.first } let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) } - subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossier(dossier, true) } + subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), true) } before do dossier.champs_private << create(:champ_piece_justificative, :with_piece_justificative_file, private: true, dossier: dossier) From 97443e2ff66e58ff2958fd0c50b91de61de6ade5 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 5 Apr 2022 14:22:23 +0200 Subject: [PATCH 04/19] inline create_list_from_dossier into caller --- app/lib/active_storage/downloadable_file.rb | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 85a3c586f..98ef3994e 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -1,18 +1,14 @@ class ActiveStorage::DownloadableFile - def self.create_list_from_dossier(dossier, for_expert = false) - dossier_export = PiecesJustificativesService.generate_dossier_export(dossier) - pjs = [dossier_export] + PiecesJustificativesService.liste_documents(dossier, for_expert) - pjs.map do |piece_justificative| - [ - piece_justificative, - "dossier-#{dossier.id}/#{self.timestamped_filename(piece_justificative)}" - ] - end - end - def self.create_list_from_dossiers(dossiers, for_expert = false) dossiers.flat_map do |dossier| - create_list_from_dossier(dossier, for_expert) + dossier_export = PiecesJustificativesService.generate_dossier_export(dossier) + pjs = [dossier_export] + PiecesJustificativesService.liste_documents(dossier, for_expert) + pjs.map do |piece_justificative| + [ + piece_justificative, + "dossier-#{dossier.id}/#{self.timestamped_filename(piece_justificative)}" + ] + end end end From d5241381eb816749b3d17415a31756c0671ce729 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 22:16:33 +0200 Subject: [PATCH 05/19] extract pj_path method --- app/lib/active_storage/downloadable_file.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 98ef3994e..2cbbd4c75 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -3,17 +3,19 @@ class ActiveStorage::DownloadableFile dossiers.flat_map do |dossier| dossier_export = PiecesJustificativesService.generate_dossier_export(dossier) pjs = [dossier_export] + PiecesJustificativesService.liste_documents(dossier, for_expert) - pjs.map do |piece_justificative| - [ - piece_justificative, - "dossier-#{dossier.id}/#{self.timestamped_filename(piece_justificative)}" - ] - end + pjs.map { |piece_justificative| pj_and_path(dossier, piece_justificative) } end end private + def self.pj_and_path(dossier, pj) + [ + pj, + "dossier-#{dossier.id}/#{self.timestamped_filename(pj)}" + ] + end + def self.timestamped_filename(attachment) # we pad the original file name with a timestamp # and a short id in order to help identify multiple versions and avoid name collisions From 51a6145d96a6479f1bda3031476c4dfb1810341b Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 22:24:14 +0200 Subject: [PATCH 06/19] put dossier_pdf apart --- app/lib/active_storage/downloadable_file.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 2cbbd4c75..41713ac0b 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -1,10 +1,13 @@ class ActiveStorage::DownloadableFile def self.create_list_from_dossiers(dossiers, for_expert = false) - dossiers.flat_map do |dossier| - dossier_export = PiecesJustificativesService.generate_dossier_export(dossier) - pjs = [dossier_export] + PiecesJustificativesService.liste_documents(dossier, for_expert) + pj_and_paths = dossiers.map { |d| pj_and_path(d, PiecesJustificativesService.generate_dossier_export(d)) } + + pj_and_paths += dossiers.flat_map do |dossier| + pjs = PiecesJustificativesService.liste_documents(dossier, for_expert) pjs.map { |piece_justificative| pj_and_path(dossier, piece_justificative) } end + + pj_and_paths end private From 7ac1288905b88deee0056a22bd6ae84f94d6b9e0 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 22:53:06 +0200 Subject: [PATCH 07/19] pj_service take a dossier collection ! --- app/lib/active_storage/downloadable_file.rb | 11 +++-------- app/services/pieces_justificatives_service.rb | 12 +++++++----- spec/services/pieces_justificatives_service_spec.rb | 6 +++--- spec/services/procedure_archive_service_spec.rb | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 41713ac0b..93842d5cb 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -1,13 +1,8 @@ class ActiveStorage::DownloadableFile def self.create_list_from_dossiers(dossiers, for_expert = false) - pj_and_paths = dossiers.map { |d| pj_and_path(d, PiecesJustificativesService.generate_dossier_export(d)) } - - pj_and_paths += dossiers.flat_map do |dossier| - pjs = PiecesJustificativesService.liste_documents(dossier, for_expert) - pjs.map { |piece_justificative| pj_and_path(dossier, piece_justificative) } - end - - pj_and_paths + dossiers + .map { |d| pj_and_path(d, PiecesJustificativesService.generate_dossier_export(d)) } + + PiecesJustificativesService.liste_documents(dossiers, for_expert) end private diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 63192f350..f836d9989 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,10 +1,12 @@ class PiecesJustificativesService - def self.liste_documents(dossier, for_expert) - pjs_champs = pjs_for_champs(dossier, for_expert) - pjs_commentaires = pjs_for_commentaires(dossier) - pjs_dossier = pjs_for_dossier(dossier, for_expert) + def self.liste_documents(dossiers, for_expert) + dossiers.flat_map do |dossier| + pjs = pjs_for_champs(dossier, for_expert) + + pjs_for_commentaires(dossier) + + pjs_for_dossier(dossier, for_expert) - pjs_champs + pjs_commentaires + pjs_dossier + pjs.map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier, piece_justificative) } + end end def self.serialize_types_de_champ_as_type_pj(revision) diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb index 8fbdd43eb..0f2dd55a9 100644 --- a/spec/services/pieces_justificatives_service_spec.rb +++ b/spec/services/pieces_justificatives_service_spec.rb @@ -16,15 +16,15 @@ describe PiecesJustificativesService do end describe '.liste_documents' do - subject { PiecesJustificativesService.liste_documents(dossier, false) } + subject { PiecesJustificativesService.liste_documents(Dossier.where(id: dossier.id), false) } it "doesn't return sensitive documents like titre_identite" do expect(champ_identite.piece_justificative_file).to be_attached - expect(subject.any? { |piece| piece.name == 'piece_justificative_file' }).to be_falsy + expect(subject.any? { |piece, _| piece.name == 'piece_justificative_file' }).to be_falsy end it "returns operation logs of the dossier" do - expect(subject.any? { |piece| piece.name == 'serialized' }).to be_truthy + expect(subject.any? { |piece, _| piece.name == 'serialized' }).to be_truthy end end diff --git a/spec/services/procedure_archive_service_spec.rb b/spec/services/procedure_archive_service_spec.rb index cb7e62712..e0ea87ccc 100644 --- a/spec/services/procedure_archive_service_spec.rb +++ b/spec/services/procedure_archive_service_spec.rb @@ -106,7 +106,7 @@ describe ProcedureArchiveService do ) end - let(:documents) { [pj, bad_pj] } + let(:documents) { [pj, bad_pj].map { |p| ActiveStorage::DownloadableFile.pj_and_path(dossier, p) } } before do allow(PiecesJustificativesService).to receive(:liste_documents).and_return(documents) end From 34b0578d70b55deeeb82c12b87561f632490d247 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 23:00:54 +0200 Subject: [PATCH 08/19] pj_and_path only take dossier id --- app/lib/active_storage/downloadable_file.rb | 6 +++--- app/services/pieces_justificatives_service.rb | 2 +- spec/services/procedure_archive_service_spec.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 93842d5cb..0cbacfe95 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -1,16 +1,16 @@ class ActiveStorage::DownloadableFile def self.create_list_from_dossiers(dossiers, for_expert = false) dossiers - .map { |d| pj_and_path(d, PiecesJustificativesService.generate_dossier_export(d)) } + + .map { |d| pj_and_path(d.id, PiecesJustificativesService.generate_dossier_export(d)) } + PiecesJustificativesService.liste_documents(dossiers, for_expert) end private - def self.pj_and_path(dossier, pj) + def self.pj_and_path(dossier_id, pj) [ pj, - "dossier-#{dossier.id}/#{self.timestamped_filename(pj)}" + "dossier-#{dossier_id}/#{self.timestamped_filename(pj)}" ] end diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index f836d9989..749c2037a 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -5,7 +5,7 @@ class PiecesJustificativesService pjs_for_commentaires(dossier) + pjs_for_dossier(dossier, for_expert) - pjs.map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier, piece_justificative) } + pjs.map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, piece_justificative) } end end diff --git a/spec/services/procedure_archive_service_spec.rb b/spec/services/procedure_archive_service_spec.rb index e0ea87ccc..72c99a62a 100644 --- a/spec/services/procedure_archive_service_spec.rb +++ b/spec/services/procedure_archive_service_spec.rb @@ -106,7 +106,7 @@ describe ProcedureArchiveService do ) end - let(:documents) { [pj, bad_pj].map { |p| ActiveStorage::DownloadableFile.pj_and_path(dossier, p) } } + let(:documents) { [pj, bad_pj].map { |p| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, p) } } before do allow(PiecesJustificativesService).to receive(:liste_documents).and_return(documents) end From 5631141a467c558eac7fa4e137b7f7f6cd5cdba9 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 23:08:01 +0200 Subject: [PATCH 09/19] fetch pjs_for_champ by dossiers --- app/services/pieces_justificatives_service.rb | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 749c2037a..c6e94c8b0 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,12 +1,15 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) - dossiers.flat_map do |dossier| - pjs = pjs_for_champs(dossier, for_expert) + - pjs_for_commentaires(dossier) + + pj_and_paths = pjs_for_champs(dossiers, for_expert) + + pj_and_paths += dossiers.flat_map do |dossier| + pjs = pjs_for_commentaires(dossier) + pjs_for_dossier(dossier, for_expert) pjs.map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, piece_justificative) } end + + pj_and_paths end def self.serialize_types_de_champ_as_type_pj(revision) @@ -108,18 +111,26 @@ class PiecesJustificativesService private - def self.pjs_for_champs(dossier, for_expert = false) + def self.pjs_for_champs(dossiers, for_expert = false) champs = Champ .joins(:piece_justificative_file_attachment) - .where(type: "Champs::PieceJustificativeChamp", dossier: dossier) + .where(type: "Champs::PieceJustificativeChamp", dossier: dossiers) if for_expert champs = champs.where(private: false) end + champ_id_dossier_id = champs + .pluck(:id, :dossier_id) + .to_h + ActiveStorage::Attachment .includes(:blob) - .where(record_type: "Champ", record_id: champs.ids) + .where(record_type: "Champ", record_id: champ_id_dossier_id.keys) + .map do |a| + dossier_id = champ_id_dossier_id[a.record_id] + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end end def self.pjs_for_commentaires(dossier) From 11aedb2dc86e570ecc745b318b36f8aad4d882cb Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 23:15:10 +0200 Subject: [PATCH 10/19] fetch pjs_for_commentaires by dossiers --- app/services/pieces_justificatives_service.rb | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index c6e94c8b0..c36dbfada 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,12 +1,11 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) - pj_and_paths = pjs_for_champs(dossiers, for_expert) + pj_and_paths = pjs_for_champs(dossiers, for_expert) + + pjs_for_commentaires(dossiers) pj_and_paths += dossiers.flat_map do |dossier| - pjs = pjs_for_commentaires(dossier) + - pjs_for_dossier(dossier, for_expert) - - pjs.map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, piece_justificative) } + pjs_for_dossier(dossier, for_expert) + .map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, piece_justificative) } end pj_and_paths @@ -133,14 +132,20 @@ class PiecesJustificativesService end end - def self.pjs_for_commentaires(dossier) - commentaires = Commentaire + def self.pjs_for_commentaires(dossiers) + commentaire_id_dossier_id = Commentaire .joins(:piece_jointe_attachment) - .where(dossier: dossier) + .where(dossier: dossiers) + .pluck(:id, :dossier_id) + .to_h ActiveStorage::Attachment .includes(:blob) - .where(record_type: "Commentaire", record_id: commentaires.ids) + .where(record_type: "Commentaire", record_id: commentaire_id_dossier_id.keys) + .map do |a| + dossier_id = commentaire_id_dossier_id[a.record_id] + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end end def self.pjs_for_dossier(dossier, for_expert = false) From e1afb35ca256b5f21493bb4c562c7e31a2daff37 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 23:40:20 +0200 Subject: [PATCH 11/19] fetch pjs_for_dossier by dossiers put all bills in bills folder --- app/lib/active_storage/downloadable_file.rb | 7 ++ app/services/pieces_justificatives_service.rb | 79 ++++++++++++------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb index 0cbacfe95..3f38007be 100644 --- a/app/lib/active_storage/downloadable_file.rb +++ b/app/lib/active_storage/downloadable_file.rb @@ -7,6 +7,13 @@ class ActiveStorage::DownloadableFile private + def self.bill_and_path(bill) + [ + bill, + "bills/#{self.timestamped_filename(bill)}" + ] + end + def self.pj_and_path(dossier_id, pj) [ pj, diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index c36dbfada..424db58b2 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,14 +1,8 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) - pj_and_paths = pjs_for_champs(dossiers, for_expert) + - pjs_for_commentaires(dossiers) - - pj_and_paths += dossiers.flat_map do |dossier| - pjs_for_dossier(dossier, for_expert) - .map { |piece_justificative| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, piece_justificative) } - end - - pj_and_paths + pjs_for_champs(dossiers, for_expert) + + pjs_for_commentaires(dossiers) + + pjs_for_dossier(dossiers, for_expert) end def self.serialize_types_de_champ_as_type_pj(revision) @@ -148,57 +142,82 @@ class PiecesJustificativesService end end - def self.pjs_for_dossier(dossier, for_expert = false) - pjs = motivation(dossier) + - attestation(dossier) + - etablissement(dossier) + def self.pjs_for_dossier(dossiers, for_expert = false) + pjs = motivations(dossiers) + + attestations(dossiers) + + etablissements(dossiers) if !for_expert - pjs += operation_logs_and_signatures(dossier) + pjs += operation_logs_and_signatures(dossiers) end pjs end - def self.etablissement(dossier) - etablissement = Etablissement.where(dossier: dossier) + def self.etablissements(dossiers) + etablissement_id_dossier_id = Etablissement + .where(dossier: dossiers) + .pluck(:id, :dossier_id) + .to_h ActiveStorage::Attachment .includes(:blob) - .where(record_type: "Etablissement", record_id: etablissement) + .where(record_type: "Etablissement", record_id: etablissement_id_dossier_id.keys) + .map do |a| + dossier_id = etablissement_id_dossier_id[a.record_id] + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end end - def self.motivation(dossier) + def self.motivations(dossiers) ActiveStorage::Attachment .includes(:blob) - .where(record_type: "Dossier", name: "justificatif_motivation", record_id: dossier) + .where(record_type: "Dossier", name: "justificatif_motivation", record_id: dossiers) + .map do |a| + dossier_id = a.record_id + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end end - def self.attestation(dossier) - attestation = Attestation + def self.attestations(dossiers) + attestation_id_dossier_id = Attestation .joins(:pdf_attachment) - .where(dossier: dossier) + .where(dossier: dossiers) + .pluck(:id, :dossier_id) + .to_h ActiveStorage::Attachment .includes(:blob) - .where(record_type: "Attestation", record_id: attestation) + .where(record_type: "Attestation", record_id: attestation_id_dossier_id.keys) + .map do |a| + dossier_id = attestation_id_dossier_id[a.record_id] + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end end - def self.operation_logs_and_signatures(dossier) - dol_ids_bill_id = DossierOperationLog - .where(dossier: dossier) - .pluck(:id, :bill_signature_id) + def self.operation_logs_and_signatures(dossiers) + dol_id_dossier_id_bill_id = DossierOperationLog + .where(dossier: dossiers) + .pluck(:id, :dossier_id, :bill_signature_id) - dol_ids = dol_ids_bill_id.map(&:first) - bill_ids = dol_ids_bill_id.map(&:second).uniq.compact + dol_id_dossier_id = dol_id_dossier_id_bill_id + .map { |dol_id, dossier_id, _| [dol_id, dossier_id] } + .to_h + + bill_ids = dol_id_dossier_id_bill_id.map(&:third).uniq.compact serialized_dols = ActiveStorage::Attachment .includes(:blob) - .where(record_type: "DossierOperationLog", record_id: dol_ids) + .where(record_type: "DossierOperationLog", record_id: dol_id_dossier_id.keys) + .map do |a| + dossier_id = dol_id_dossier_id[a.record_id] + ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) + end bill_docs = ActiveStorage::Attachment .includes(:blob) .where(record_type: "BillSignature", record_id: bill_ids) + .map { |bill| ActiveStorage::DownloadableFile.bill_and_path(bill) } serialized_dols + bill_docs end From c27d9a01f23c4ef71e3b407c268f14dc3ea2f5fb Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Apr 2022 23:53:29 +0200 Subject: [PATCH 12/19] fetch documents by batch to avoid huge memory load --- app/services/pieces_justificatives_service.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 424db58b2..2879890f3 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,8 +1,10 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) - pjs_for_champs(dossiers, for_expert) + - pjs_for_commentaires(dossiers) + - pjs_for_dossier(dossiers, for_expert) + dossiers.in_batches.flat_map do |batch| + pjs_for_champs(batch, for_expert) + + pjs_for_commentaires(batch) + + pjs_for_dossier(batch, for_expert) + end end def self.serialize_types_de_champ_as_type_pj(revision) From f24f6ee105e6180dfe5e3f2d27fb46e8f52c991f Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 5 Apr 2022 15:10:22 +0200 Subject: [PATCH 13/19] extract operation_logs_and_signature from pjs_for_dossiers --- app/services/pieces_justificatives_service.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 2879890f3..98a119107 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,9 +1,15 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) dossiers.in_batches.flat_map do |batch| - pjs_for_champs(batch, for_expert) + + pjs = pjs_for_champs(batch, for_expert) + pjs_for_commentaires(batch) + - pjs_for_dossier(batch, for_expert) + pjs_for_dossier(batch) + + if !for_expert + pjs += operation_logs_and_signatures(dossiers) + end + + pjs end end @@ -144,16 +150,10 @@ class PiecesJustificativesService end end - def self.pjs_for_dossier(dossiers, for_expert = false) - pjs = motivations(dossiers) + + def self.pjs_for_dossier(dossiers) + motivations(dossiers) + attestations(dossiers) + etablissements(dossiers) - - if !for_expert - pjs += operation_logs_and_signatures(dossiers) - end - - pjs end def self.etablissements(dossiers) From e2a54e3ee3b56e936759eedcfdd36f7845c45bfa Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 5 Apr 2022 15:30:23 +0200 Subject: [PATCH 14/19] extract bill_ids per batch, and catch them all afterwards to avoid duplicate --- app/services/pieces_justificatives_service.rb | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 98a119107..0bc94b5ad 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -1,16 +1,30 @@ class PiecesJustificativesService def self.liste_documents(dossiers, for_expert) - dossiers.in_batches.flat_map do |batch| + bill_ids = [] + + docs = dossiers.in_batches.flat_map do |batch| pjs = pjs_for_champs(batch, for_expert) + pjs_for_commentaires(batch) + pjs_for_dossier(batch) if !for_expert - pjs += operation_logs_and_signatures(dossiers) + # some bills are shared among operations + # so first, all the bill_ids are fetched + operation_logs, some_bill_ids = operation_logs_and_signature_ids(batch) + + pjs += operation_logs + bill_ids += some_bill_ids end pjs end + + if !for_expert + # then the bills are retrieved without duplication + docs += signatures(bill_ids.uniq) + end + + docs end def self.serialize_types_de_champ_as_type_pj(revision) @@ -197,7 +211,7 @@ class PiecesJustificativesService end end - def self.operation_logs_and_signatures(dossiers) + def self.operation_logs_and_signature_ids(dossiers) dol_id_dossier_id_bill_id = DossierOperationLog .where(dossier: dossiers) .pluck(:id, :dossier_id, :bill_signature_id) @@ -216,11 +230,13 @@ class PiecesJustificativesService ActiveStorage::DownloadableFile.pj_and_path(dossier_id, a) end - bill_docs = ActiveStorage::Attachment + [serialized_dols, bill_ids] + end + + def self.signatures(bill_ids) + ActiveStorage::Attachment .includes(:blob) .where(record_type: "BillSignature", record_id: bill_ids) .map { |bill| ActiveStorage::DownloadableFile.bill_and_path(bill) } - - serialized_dols + bill_docs end end From 951d96470100f73f2f158f6c275185c2e04a1e52 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Apr 2022 10:39:54 +0200 Subject: [PATCH 15/19] clean pj_service test --- .../pieces_justificatives_service_spec.rb | 149 ++++++++++++++---- 1 file changed, 121 insertions(+), 28 deletions(-) diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb index 0f2dd55a9..8b27a2b33 100644 --- a/spec/services/pieces_justificatives_service_spec.rb +++ b/spec/services/pieces_justificatives_service_spec.rb @@ -1,43 +1,136 @@ describe PiecesJustificativesService do - let(:procedure) { create(:procedure, :with_titre_identite) } - let(:dossier) { create(:dossier, procedure: procedure) } - let(:champ_identite) { dossier.champs.find { |c| c.type == 'Champs::TitreIdentiteChamp' } } - let(:bill_signature) do - bs = build(:bill_signature, :with_serialized, :with_signature) - bs.save(validate: false) - bs - end - - before do - champ_identite - .piece_justificative_file - .attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png") - create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature) - end - describe '.liste_documents' do - subject { PiecesJustificativesService.liste_documents(Dossier.where(id: dossier.id), false) } + let(:procedure) { create(:procedure) } + let(:dossier) { create(:dossier, procedure: procedure) } + let(:for_expert) { false } - it "doesn't return sensitive documents like titre_identite" do - expect(champ_identite.piece_justificative_file).to be_attached - expect(subject.any? { |piece, _| piece.name == 'piece_justificative_file' }).to be_falsy + subject do + PiecesJustificativesService + .liste_documents(Dossier.where(id: dossier.id), for_expert) + .map(&:first) end - it "returns operation logs of the dossier" do - expect(subject.any? { |piece, _| piece.name == 'serialized' }).to be_truthy + context 'with a pj champ' do + let(:procedure) { create(:procedure, :with_piece_justificative) } + let(:pj_champ) { dossier.champs.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } + + before { attach_file_to_champ(pj_champ) } + + it { expect(subject).to match_array([pj_champ.piece_justificative_file.attachment]) } + end + + context 'with a private pj champ' do + let(:procedure) { create(:procedure) } + let!(:private_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, private: true) } + let(:private_pj_champ) { dossier.champs_private.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } + + before { attach_file_to_champ(private_pj_champ) } + + it { expect(subject).to match_array([private_pj_champ.piece_justificative_file.attachment]) } + + context 'for expert' do + let(:for_expert) { true } + + it { expect(subject).to be_empty } + end + end + + context 'with a identite champ pj' do + let(:procedure) { create(:procedure, :with_titre_identite) } + let(:champ_identite) { dossier.champs.find { |c| c.type == 'Champs::TitreIdentiteChamp' } } + + before { attach_file_to_champ(champ_identite) } + + it "doesn't return sensitive documents like titre_identite" do + expect(champ_identite.piece_justificative_file).to be_attached + expect(subject).to be_empty + end + end + + context 'with a pj on an commentaire' do + let!(:commentaire) { create(:commentaire, :with_file, dossier: dossier) } + + it { expect(subject).to match_array(dossier.commentaires.first.piece_jointe.attachment) } + end + + context 'with a motivation' do + let(:dossier) { create(:dossier, :with_justificatif) } + + it { expect(subject).to match_array(dossier.justificatif_motivation.attachment) } + end + + context 'with an attestation' do + let(:dossier) { create(:dossier, :with_attestation) } + + it { expect(subject).to match_array(dossier.attestation.pdf.attachment) } + end + + context 'with an etablissement' do + let(:dossier) { create(:dossier, :with_entreprise) } + let(:attestation_sociale) { dossier.etablissement.entreprise_attestation_sociale } + let(:attestation_fiscale) { dossier.etablissement.entreprise_attestation_fiscale } + + before do + attach_file(attestation_sociale) + attach_file(attestation_fiscale) + end + + it { expect(subject).to match_array([attestation_sociale.attachment, attestation_fiscale.attachment]) } + end + + context 'with a bill' do + let(:bill_signature) do + bs = build(:bill_signature, :with_serialized, :with_signature) + bs.save(validate: false) + bs + end + + before { create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature) } + + let(:dossier_bs) { dossier.dossier_operation_logs.first.bill_signature } + + it "returns serialized bill and signature" do + expect(subject).to match_array([dossier_bs.serialized.attachment, dossier_bs.signature.attachment]) + end + + context 'for expert' do + let(:for_expert) { true } + + it { expect(subject).to be_empty } + end + end + + context 'with a dol' do + let(:dol) { create(:dossier_operation_log, dossier: dossier) } + + before { attach_file(dol.serialized) } + + it { expect(subject).to match_array(dol.serialized.attachment) } + + context 'for expert' do + let(:for_expert) { true } + + it { expect(subject).to be_empty } + end end end describe '.generate_dossier_export' do + let(:dossier) { create(:dossier) } + subject { PiecesJustificativesService.generate_dossier_export(dossier) } - it "generates pdf export for instructeur" do - subject - end it "doesn't update dossier" do - before_export = Time.zone.now - subject - expect(dossier.updated_at).to be <= before_export + expect { subject }.not_to change { dossier.updated_at } end end + + def attach_file_to_champ(champ) + attach_file(champ.piece_justificative_file) + end + + def attach_file(attachable) + attachable + .attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png") + end end From e2130cc2d3db7882e48a3441f6eee748174c4edc Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Apr 2022 12:02:20 +0200 Subject: [PATCH 16/19] add witness dossier --- .../pieces_justificatives_service_spec.rb | 64 +++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb index 8b27a2b33..8d0ca2e56 100644 --- a/spec/services/pieces_justificatives_service_spec.rb +++ b/spec/services/pieces_justificatives_service_spec.rb @@ -1,7 +1,5 @@ describe PiecesJustificativesService do describe '.liste_documents' do - let(:procedure) { create(:procedure) } - let(:dossier) { create(:dossier, procedure: procedure) } let(:for_expert) { false } subject do @@ -12,21 +10,33 @@ describe PiecesJustificativesService do context 'with a pj champ' do let(:procedure) { create(:procedure, :with_piece_justificative) } - let(:pj_champ) { dossier.champs.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } + let(:dossier) { create(:dossier, procedure: procedure) } + let(:witness) { create(:dossier, procedure: procedure) } - before { attach_file_to_champ(pj_champ) } + let(:pj_champ) { -> (d) { d.champs.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } } - it { expect(subject).to match_array([pj_champ.piece_justificative_file.attachment]) } + before do + attach_file_to_champ(pj_champ.call(dossier)) + attach_file_to_champ(pj_champ.call(witness)) + end + + it { expect(subject).to match_array([pj_champ.call(dossier).piece_justificative_file.attachment]) } end context 'with a private pj champ' do let(:procedure) { create(:procedure) } + let(:dossier) { create(:dossier, procedure: procedure) } + let(:witness) { create(:dossier, procedure: procedure) } + let!(:private_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, private: true) } - let(:private_pj_champ) { dossier.champs_private.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } + let(:private_pj_champ) { -> (d) { d.champs_private.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } } - before { attach_file_to_champ(private_pj_champ) } + before do + attach_file_to_champ(private_pj_champ.call(dossier)) + attach_file_to_champ(private_pj_champ.call(witness)) + end - it { expect(subject).to match_array([private_pj_champ.piece_justificative_file.attachment]) } + it { expect(subject).to match_array([private_pj_champ.call(dossier).piece_justificative_file.attachment]) } context 'for expert' do let(:for_expert) { true } @@ -37,6 +47,9 @@ describe PiecesJustificativesService do context 'with a identite champ pj' do let(:procedure) { create(:procedure, :with_titre_identite) } + let(:dossier) { create(:dossier, procedure: procedure) } + let(:witness) { create(:dossier, procedure: procedure) } + let(:champ_identite) { dossier.champs.find { |c| c.type == 'Champs::TitreIdentiteChamp' } } before { attach_file_to_champ(champ_identite) } @@ -48,19 +61,25 @@ describe PiecesJustificativesService do end context 'with a pj on an commentaire' do + let(:dossier) { create(:dossier) } + let(:witness) { create(:dossier) } + let!(:commentaire) { create(:commentaire, :with_file, dossier: dossier) } + let!(:witness_commentaire) { create(:commentaire, :with_file, dossier: witness) } it { expect(subject).to match_array(dossier.commentaires.first.piece_jointe.attachment) } end context 'with a motivation' do let(:dossier) { create(:dossier, :with_justificatif) } + let!(:witness) { create(:dossier, :with_justificatif) } it { expect(subject).to match_array(dossier.justificatif_motivation.attachment) } end context 'with an attestation' do let(:dossier) { create(:dossier, :with_attestation) } + let!(:witness) { create(:dossier, :with_attestation) } it { expect(subject).to match_array(dossier.attestation.pdf.attachment) } end @@ -70,6 +89,10 @@ describe PiecesJustificativesService do let(:attestation_sociale) { dossier.etablissement.entreprise_attestation_sociale } let(:attestation_fiscale) { dossier.etablissement.entreprise_attestation_fiscale } + let!(:witness) { create(:dossier, :with_entreprise) } + let!(:witness_attestation_sociale) { witness.etablissement.entreprise_attestation_sociale } + let!(:witness_attestation_fiscale) { witness.etablissement.entreprise_attestation_fiscale } + before do attach_file(attestation_sociale) attach_file(attestation_fiscale) @@ -79,13 +102,25 @@ describe PiecesJustificativesService do end context 'with a bill' do + let(:dossier) { create(:dossier) } + let(:witness) { create(:dossier) } + let(:bill_signature) do bs = build(:bill_signature, :with_serialized, :with_signature) bs.save(validate: false) bs end - before { create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature) } + let(:witness_bill_signature) do + bs = build(:bill_signature, :with_serialized, :with_signature) + bs.save(validate: false) + bs + end + + before do + create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature) + create(:dossier_operation_log, dossier: witness, bill_signature: witness_bill_signature) + end let(:dossier_bs) { dossier.dossier_operation_logs.first.bill_signature } @@ -101,9 +136,16 @@ describe PiecesJustificativesService do end context 'with a dol' do - let(:dol) { create(:dossier_operation_log, dossier: dossier) } + let(:dossier) { create(:dossier) } + let(:witness) { create(:dossier) } - before { attach_file(dol.serialized) } + let(:dol) { create(:dossier_operation_log, dossier: dossier) } + let(:witness_dol) { create(:dossier_operation_log, dossier: witness) } + + before do + attach_file(dol.serialized) + attach_file(witness_dol.serialized) + end it { expect(subject).to match_array(dol.serialized.attachment) } From 4f73c6105fc34660621ea3fbfaf9865e40cd37e0 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Apr 2022 12:05:58 +0200 Subject: [PATCH 17/19] remove duplicate spec --- .../active_storage/downloadable_file_spec.rb | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/spec/lib/active_storage/downloadable_file_spec.rb b/spec/lib/active_storage/downloadable_file_spec.rb index 011614265..f2e35f767 100644 --- a/spec/lib/active_storage/downloadable_file_spec.rb +++ b/spec/lib/active_storage/downloadable_file_spec.rb @@ -8,67 +8,5 @@ describe ActiveStorage::DownloadableFile do it { expect(list.length).to eq 1 } it { expect(list.first[0].name).to eq "pdf_export_for_instructeur" } end - - context 'when there is a piece_justificative' do - before do - dossier.champs << create(:champ_piece_justificative, :with_piece_justificative_file, dossier: dossier) - end - - it { expect(list.length).to eq 2 } - end - - context 'when there is a private piece_justificative' do - before do - dossier.champs_private << create(:champ_piece_justificative, :with_piece_justificative_file, private: true, dossier: dossier) - end - - it { expect(list.length).to eq 2 } - end - - context 'when there is a repetition bloc' do - before do - dossier.champs << create(:champ_repetition_with_piece_jointe, dossier: dossier) - end - - it 'should have 4 piece_justificatives' do - expect(list.size).to eq 5 - end - end - - context 'when there is a message with no attachment' do - before do - dossier.commentaires << create(:commentaire, dossier: dossier) - end - - it { expect(list.length).to eq 1 } - end - - context 'when there is a message with an attachment' do - before do - dossier.commentaires << create(:commentaire, :with_file, dossier: dossier) - end - - it { expect(list.length).to eq 2 } - end - - context 'when the files are asked by an expert with piece justificative and private piece justificative' do - let(:expert) { create(:expert) } - let(:instructeur) { create(:instructeur) } - let(:procedure) { create(:procedure, :published, :with_piece_justificative, instructeurs: [instructeur]) } - let(:experts_procedure) { create(:experts_procedure, expert: expert, procedure: procedure) } - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } - let(:champ) { dossier.champs.first } - let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) } - - subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), true) } - - before do - dossier.champs_private << create(:champ_piece_justificative, :with_piece_justificative_file, private: true, dossier: dossier) - - dossier.champs << create(:champ_piece_justificative, :with_piece_justificative_file, dossier: dossier) - end - - it { expect(list.length).to eq 2 } - end end end From 94fa247d8d2dd82a075db399d84a39a23c20a64c Mon Sep 17 00:00:00 2001 From: kleph Date: Wed, 6 Apr 2022 11:19:28 +0200 Subject: [PATCH 18/19] Use the same env vars for setup and deploy --- config/deploy.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/deploy.rb b/config/deploy.rb index b5831b7e6..e289888f8 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -26,18 +26,18 @@ shared_dirs = [ 'vendor/bundle' ] -set :domain, ENV.fetch('domain') +set :domain, ENV.fetch('DOMAINS') set :deploy_to, deploy_to # rubocop:disable DS/ApplicationName set :repository, 'https://github.com/betagouv/demarches-simplifiees.fr.git' # rubocop:enable DS/ApplicationName -set :branch, ENV.fetch('branch') +set :branch, ENV.fetch('BRANCH') set :forward_agent, true set :user, 'ds' set :shared_dirs, shared_dirs set :rbenv_path, "/home/ds/.rbenv/bin/rbenv" -puts "Deploy to #{ENV.fetch('domain')}, branch: #{ENV.fetch('branch')}" +puts "Deploy to #{ENV.fetch('DOMAINS')}, branch: #{ENV.fetch('BRANCH')}" # This task is the environment that is loaded for most commands, such as # `mina deploy` or `mina rake`. From 90dd5bc9c58ee2ccb90c9a1d835f1fa6b78ec0dd Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Fri, 8 Apr 2022 13:16:08 +0200 Subject: [PATCH 19/19] fix(dossiers): dossier extend_conservation actually works --- .../instructeurs/dossiers_controller.rb | 2 +- app/controllers/users/dossiers_controller.rb | 2 +- app/graphql/types/dossier_type.rb | 2 +- app/helpers/dossier_helper.rb | 3 +- app/models/dossier.rb | 29 +++++++--- ...8100411_fix_dossiers_expiration_dates.rake | 51 ++++++++++++++++ spec/models/dossier_spec.rb | 58 ++++++++++++++++++- 7 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 lib/tasks/deployment/20220408100411_fix_dossiers_expiration_dates.rake diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index e941f50e3..9e8feb9ae 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -20,7 +20,7 @@ module Instructeurs end def extend_conservation - dossier.update(conservation_extension: dossier.conservation_extension + 1.month) + dossier.extend_conservation(1.month) flash[:notice] = t('views.instructeurs.dossiers.archived_dossier') redirect_back(fallback_location: instructeur_dossier_path(@dossier.procedure, @dossier)) end diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index f352bc4d2..765b4b19b 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -174,7 +174,7 @@ module Users end def extend_conservation - dossier.update(conservation_extension: dossier.conservation_extension + dossier.procedure.duree_conservation_dossiers_dans_ds.months) + dossier.extend_conservation(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 diff --git a/app/graphql/types/dossier_type.rb b/app/graphql/types/dossier_type.rb index 374a61c7f..ff4dbd404 100644 --- a/app/graphql/types/dossier_type.rb +++ b/app/graphql/types/dossier_type.rb @@ -63,7 +63,7 @@ module Types def date_expiration if !object.en_instruction? - object.expiration_date.presence || object.approximative_expiration_date + object.expiration_date end end diff --git a/app/helpers/dossier_helper.rb b/app/helpers/dossier_helper.rb index a0d9f1905..032b5cf8d 100644 --- a/app/helpers/dossier_helper.rb +++ b/app/helpers/dossier_helper.rb @@ -99,8 +99,7 @@ module DossierHelper end def safe_expiration_date(dossier) - date = dossier.expiration_date.presence || dossier.approximative_expiration_date - l(date, format: '%d/%m/%Y') + l(dossier.expiration_date, format: '%d/%m/%Y') end def annuaire_link(siren) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index fbef6d1a3..e32aa99db 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -573,7 +573,7 @@ class Dossier < ApplicationRecord ].any? end - def approximative_expiration_date_reference + def expiration_date_reference if brouillon? created_at elsif en_construction? @@ -581,24 +581,28 @@ class Dossier < ApplicationRecord elsif termine? processed_at else - fail "approximative_expiration_date_reference should not be called in state #{self.state}" + fail "expiration_date_reference should not be called in state #{self.state}" end end - def approximative_expiration_date + def expiration_date_with_extention [ - approximative_expiration_date_reference, + expiration_date_reference, conservation_extension, procedure.duree_conservation_dossiers_dans_ds.months - ].sum - REMAINING_WEEKS_BEFORE_EXPIRATION.weeks + ].sum + end + + def expiration_notification_date + expiration_date_with_extention - REMAINING_WEEKS_BEFORE_EXPIRATION.weeks end def close_to_expiration? return false if en_instruction? - approximative_expiration_date < Time.zone.now + expiration_notification_date < Time.zone.now end - def expiration_date + def after_notification_expiration_date if brouillon? && brouillon_close_to_expiration_notice_sent_at.present? brouillon_close_to_expiration_notice_sent_at + duration_after_notice elsif en_construction? && en_construction_close_to_expiration_notice_sent_at.present? @@ -608,6 +612,10 @@ class Dossier < ApplicationRecord end end + def expiration_date + after_notification_expiration_date.presence || expiration_date_with_extention + end + def duration_after_notice MONTHS_AFTER_EXPIRATION.month + DAYS_AFTER_EXPIRATION.days end @@ -616,6 +624,13 @@ class Dossier < ApplicationRecord brouillon? || en_construction? end + def extend_conservation(conservation_extension) + update(conservation_extension: self.conservation_extension + conservation_extension, + brouillon_close_to_expiration_notice_sent_at: nil, + en_construction_close_to_expiration_notice_sent_at: nil, + termine_close_to_expiration_notice_sent_at: nil) + end + def show_groupe_instructeur_details? procedure.routee? && groupe_instructeur.present? && (!procedure.feature_enabled?(:procedure_routage_api) || !defaut_groupe_instructeur?) end diff --git a/lib/tasks/deployment/20220408100411_fix_dossiers_expiration_dates.rake b/lib/tasks/deployment/20220408100411_fix_dossiers_expiration_dates.rake new file mode 100644 index 000000000..179054f97 --- /dev/null +++ b/lib/tasks/deployment/20220408100411_fix_dossiers_expiration_dates.rake @@ -0,0 +1,51 @@ +namespace :after_party do + desc 'Deployment task: fix_dossiers_expiration_dates' + task fix_dossiers_expiration_dates: :environment do + puts "Running deploy task 'fix_dossiers_expiration_dates'" + + duree_conservation = "procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month'" + + expiration_after_notice_brouillon = "dossiers.brouillon_close_to_expiration_notice_sent_at + INTERVAL '#{Dossier::INTERVAL_EXPIRATION}'" + expiration_with_extention_brouillon = "dossiers.created_at + dossiers.conservation_extension + (#{duree_conservation}) - INTERVAL '#{Dossier::INTERVAL_BEFORE_EXPIRATION}'" + dossiers_brouillon = Dossier + .joins(:procedure) + .state_brouillon + .visible_by_user + .where.not(brouillon_close_to_expiration_notice_sent_at: nil) + .where.not(conservation_extension: 0.seconds) + .where("(#{expiration_after_notice_brouillon}) < (#{expiration_with_extention_brouillon})") + + expiration_after_notice_en_construction = "dossiers.en_construction_close_to_expiration_notice_sent_at + INTERVAL '#{Dossier::INTERVAL_EXPIRATION}'" + expiration_with_extention_en_construction = "dossiers.en_construction_at + dossiers.conservation_extension + (#{duree_conservation}) - INTERVAL '#{Dossier::INTERVAL_BEFORE_EXPIRATION}'" + dossiers_en_construction = Dossier + .joins(:procedure) + .state_en_construction + .visible_by_user_or_administration + .where.not(en_construction_close_to_expiration_notice_sent_at: nil) + .where.not(conservation_extension: 0.seconds) + .where("(#{expiration_after_notice_en_construction}) < (#{expiration_with_extention_en_construction})") + + expiration_after_notice_termine = "dossiers.termine_close_to_expiration_notice_sent_at + INTERVAL '#{Dossier::INTERVAL_EXPIRATION}'" + expiration_with_extention_termine = "dossiers.processed_at + dossiers.conservation_extension + (#{duree_conservation}) - INTERVAL '#{Dossier::INTERVAL_BEFORE_EXPIRATION}'" + dossiers_termine = Dossier + .joins(:procedure) + .state_termine + .visible_by_user_or_administration + .where.not(termine_close_to_expiration_notice_sent_at: nil) + .where.not(conservation_extension: 0.seconds) + .where("(#{expiration_after_notice_termine}) < (#{expiration_with_extention_termine})") + + rake_puts "brouillon: #{dossiers_brouillon.count}" + rake_puts "en_construction: #{dossiers_en_construction.count}" + rake_puts "termine: #{dossiers_termine.count}" + + dossiers_brouillon.update_all(brouillon_close_to_expiration_notice_sent_at: nil) + dossiers_en_construction.update_all(en_construction_close_to_expiration_notice_sent_at: nil) + dossiers_termine.update_all(termine_close_to_expiration_notice_sent_at: nil) + + # 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/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 2b8298a50..f8ec28d1f 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -40,6 +40,7 @@ describe Dossier do let(:procedure) { create(:procedure, :published, duree_conservation_dossiers_dans_ds: 6) } let!(:young_dossier) { create(:dossier, :en_construction, procedure: procedure) } let!(:expiring_dossier) { create(:dossier, created_at: 175.days.ago, procedure: procedure) } + let!(:expiring_dossier_with_notification) { create(:dossier, created_at: 175.days.ago, brouillon_close_to_expiration_notice_sent_at: Time.zone.now, procedure: procedure) } let!(:just_expired_dossier) { create(:dossier, created_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } let!(:long_expired_dossier) { create(:dossier, created_at: 1.year.ago, procedure: procedure) } @@ -52,13 +53,27 @@ describe Dossier do is_expected.to include(long_expired_dossier) end + it do + expect(expiring_dossier.close_to_expiration?).to be_truthy + expect(expiring_dossier_with_notification.close_to_expiration?).to be_truthy + end + context 'does not include an expiring dossier that has been postponed' do before do - expiring_dossier.update(conservation_extension: 1.month) + expiring_dossier.extend_conservation(1.month) + expiring_dossier_with_notification.extend_conservation(1.month) expiring_dossier.reload + expiring_dossier_with_notification.reload end it { is_expected.not_to include(expiring_dossier) } + it do + expect(expiring_dossier.close_to_expiration?).to be_falsey + expect(expiring_dossier_with_notification.close_to_expiration?).to be_falsey + + expect(expiring_dossier.expiration_date).to eq(expiring_dossier.expiration_date_with_extention) + expect(expiring_dossier_with_notification.expiration_date).to eq(expiring_dossier_with_notification.expiration_date_with_extention) + end end context 'when .close_to_expiration' do @@ -76,6 +91,7 @@ describe Dossier 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_construction, en_construction_at: 175.days.ago, procedure: procedure) } + let!(:expiring_dossier_with_notification) { create(:dossier, :en_construction, en_construction_at: 175.days.ago, en_construction_close_to_expiration_notice_sent_at: Time.zone.now, procedure: procedure) } let!(:just_expired_dossier) { create(:dossier, :en_construction, en_construction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } let!(:long_expired_dossier) { create(:dossier, :en_construction, en_construction_at: 1.year.ago, procedure: procedure) } @@ -88,13 +104,27 @@ describe Dossier do is_expected.to include(long_expired_dossier) end + it do + expect(expiring_dossier.close_to_expiration?).to be_truthy + expect(expiring_dossier_with_notification.close_to_expiration?).to be_truthy + end + context 'does not include an expiring dossier that has been postponed' do before do - expiring_dossier.update(conservation_extension: 1.month) + expiring_dossier.extend_conservation(1.month) + expiring_dossier_with_notification.extend_conservation(1.month) expiring_dossier.reload + expiring_dossier_with_notification.reload end it { is_expected.not_to include(expiring_dossier) } + it do + expect(expiring_dossier.close_to_expiration?).to be_falsey + expect(expiring_dossier_with_notification.close_to_expiration?).to be_falsey + + expect(expiring_dossier.expiration_date).to eq(expiring_dossier.expiration_date_with_extention) + expect(expiring_dossier_with_notification.expiration_date).to eq(expiring_dossier_with_notification.expiration_date_with_extention) + end end context 'when .close_to_expiration' do @@ -121,6 +151,7 @@ describe Dossier do 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!(:expiring_dossier_with_notification) { create(:dossier, state: :accepte, procedure: procedure, processed_at: 175.days.ago, termine_close_to_expiration_notice_sent_at: Time.zone.now) } 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) } @@ -133,6 +164,29 @@ describe Dossier do is_expected.to include(long_expired_dossier) end + it do + expect(expiring_dossier.close_to_expiration?).to be_truthy + expect(expiring_dossier_with_notification.close_to_expiration?).to be_truthy + end + + context 'does not include an expiring dossier that has been postponed' do + before do + expiring_dossier.extend_conservation(1.month) + expiring_dossier_with_notification.extend_conservation(1.month) + expiring_dossier.reload + expiring_dossier_with_notification.reload + end + + it { is_expected.not_to include(expiring_dossier) } + it do + expect(expiring_dossier.close_to_expiration?).to be_falsey + expect(expiring_dossier_with_notification.close_to_expiration?).to be_falsey + + expect(expiring_dossier.expiration_date).to eq(expiring_dossier.expiration_date_with_extention) + expect(expiring_dossier_with_notification.expiration_date).to eq(expiring_dossier_with_notification.expiration_date_with_extention) + end + end + context 'when .close_to_expiration' do subject { Dossier.close_to_expiration } it do