diff --git a/app/controllers/instructeurs/archives_controller.rb b/app/controllers/instructeurs/archives_controller.rb
new file mode 100644
index 000000000..308f51b80
--- /dev/null
+++ b/app/controllers/instructeurs/archives_controller.rb
@@ -0,0 +1,49 @@
+module Instructeurs
+ class ArchivesController < InstructeurController
+ before_action :ensure_procedure_enabled
+
+ def index
+ @procedure = procedure
+
+ @archivable_months = archivable_months
+ @dossiers_termines = @procedure.dossiers.state_termine
+ @poids_total = ProcedureArchiveService.procedure_files_size(@procedure)
+ groupe_instructeur = current_instructeur.groupe_instructeurs.where(procedure: @procedure.id).first
+ @archives = Archive.for_groupe_instructeur(groupe_instructeur)
+ end
+
+ def create
+ type = params[:type]
+ month = Date.strptime(params[:month], '%Y-%m') if params[:month].present?
+
+ ArchiveCreationJob.perform_later(procedure, current_instructeur, type, month)
+ flash[:notice] = "Votre demande a été prise en compte. Selon le nombre de dossiers, cela peut prendre quelques minutes. Vous recevrez un courriel lorsque le fichier sera disponible."
+ end
+
+ private
+
+ def ensure_procedure_enabled
+ if !procedure.publiee?
+ flash[:alert] = "L'accès aux archives n'est pas disponible pour cette démarche, merci d'en faire la demande à l'équipe de démarches simplifiees"
+ return redirect_to instructeur_procedure_path(procedure)
+ end
+ end
+
+ def archivable_months
+ start_date = procedure.published_at.to_date
+ end_date = Time.zone.now.to_date
+
+ (start_date...end_date)
+ .map(&:beginning_of_month)
+ .uniq
+ .reverse
+ end
+
+ def procedure
+ current_instructeur
+ .procedures
+ .for_download
+ .find(params[:procedure_id])
+ end
+ end
+end
diff --git a/app/helpers/archive_helper.rb b/app/helpers/archive_helper.rb
new file mode 100644
index 000000000..b349b8793
--- /dev/null
+++ b/app/helpers/archive_helper.rb
@@ -0,0 +1,5 @@
+module ArchiveHelper
+ def can_generate_archive?(dossiers_termines, poids_total)
+ dossiers_termines.count < 100 && poids_total < 1.gigabyte
+ end
+end
diff --git a/app/models/procedure.rb b/app/models/procedure.rb
index ea0b4e570..b4760c353 100644
--- a/app/models/procedure.rb
+++ b/app/models/procedure.rb
@@ -156,6 +156,20 @@ class Procedure < ApplicationRecord
includes(:draft_revision, :published_revision, administrateurs: :user)
}
+ scope :for_download, -> {
+ includes(
+ :groupe_instructeurs,
+ dossiers: {
+ champs: [
+ piece_justificative_file_attachment: :blob,
+ champs: [
+ piece_justificative_file_attachment: :blob
+ ]
+ ]
+ }
+ )
+ }
+
validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :description, presence: true, allow_blank: false, allow_nil: false
validates :administrateurs, presence: true
diff --git a/app/views/instructeurs/archives/create.js.haml b/app/views/instructeurs/archives/create.js.haml
new file mode 100644
index 000000000..7fe9f7f0b
--- /dev/null
+++ b/app/views/instructeurs/archives/create.js.haml
@@ -0,0 +1 @@
+= render_flash(sticky: true)
diff --git a/app/views/instructeurs/archives/index.html.haml b/app/views/instructeurs/archives/index.html.haml
new file mode 100644
index 000000000..057385e69
--- /dev/null
+++ b/app/views/instructeurs/archives/index.html.haml
@@ -0,0 +1,91 @@
+- content_for(:title, "Archives pour #{@procedure.libelle}")
+
+= render partial: 'new_administrateur/breadcrumbs',
+ locals: { steps: [link_to(@procedure.libelle, instructeur_procedure_path(@procedure)),
+ 'Archives'] }
+
+.container
+ %h1 Archives
+
+ .card.featured
+ .card-title Gestion de vos archives
+ %p
+ Vous pouvez télécharger les archives des dossiers terminés depuis la publication de la procédure au format Zip.
+
+ %p
+ Cet export contient les demande déposée par l'usager et la liste des pièces justificatives transmises.
+
+ %p
+ Cet export n'est pas possible pour le moment pour les démarches à forte volumétrie.
+ Nous vous invitons à regarder
+ = link_to 'la documentation', ARCHIVAGE_DOC_URL
+ afin de voir les options à votre disposition pour mettre en place un système d'archive.
+
+ %table.table.hoverable
+ %thead
+ %tr
+ %th
+ %th Nombre de dossiers terminés
+ %th Poids estimé
+ %th Télécharger
+
+ %tbody
+ - if can_generate_archive?(@dossiers_termines, @poids_total)
+ %tr
+ - matching_archive = @archives.find_by(content_type: 'everything')
+ %td
+ Tous les dossiers
+ %td
+ = @dossiers_termines.count
+ %td
+ - if matching_archive.present? && matching_archive.available?
+ - weight = matching_archive.file.byte_size
+ - else
+ - weight = @poids_total
+ = number_to_human_size(weight)
+ %td
+ - if matching_archive.try(&:available?)
+ = link_to url_for(matching_archive.file), class: 'button primary' do
+ %span.icon.download-white
+ Télécharger
+ - elsif matching_archive.try(&:pending?)
+ %span.icon.retry
+ Archive en cours de création
+ - elsif @dossiers_termines.count > 0
+ = link_to instructeur_archives_path(@procedure, type: 'everything'), method: :post, class: "button", remote: true do
+ %span.icon.new-folder
+ Demander la création
+ - else
+ Rien à télécharger !
+ - @archivable_months.each do |month|
+ - dossiers_termines = @procedure.dossiers.processed_in_month(month)
+ - nb_dossiers_termines = dossiers_termines.count
+ - matching_archive = @archives.find_by(content_type: 'monthly', month: month)
+ %tr
+ %td
+ = I18n.l(month, format: "%B %Y")
+ %td
+ = nb_dossiers_termines
+ %td
+ - if matching_archive.present? && matching_archive.available?
+ - weight = matching_archive.file.byte_size
+ - else
+ - weight = ProcedureArchiveService::dossiers_files_size(dossiers_termines)
+ = number_to_human_size(weight)
+ %td
+ - if nb_dossiers_termines > 0
+ - if matching_archive.present?
+ - if matching_archive.status == 'generated' && matching_archive.file.attached?
+ = link_to url_for(matching_archive.file), class: 'button primary' do
+ %span.icon.download-white
+ Télécharger
+ - else
+ %span.icon.retry
+ Archive en cours de création
+ - else
+ = link_to instructeur_archives_path(@procedure, type:'monthly', month: month.strftime('%Y-%m')), method: :post, class: "button", remote: true do
+ %span.icon.new-folder
+ Démander la création
+ - else
+ Rien à télécharger !
+
diff --git a/app/views/instructeurs/procedures/_download_dossiers.html.haml b/app/views/instructeurs/procedures/_download_dossiers.html.haml
index 87c2c7417..1e0993605 100644
--- a/app/views/instructeurs/procedures/_download_dossiers.html.haml
+++ b/app/views/instructeurs/procedures/_download_dossiers.html.haml
@@ -16,3 +16,5 @@
- else
%span{ 'data-export-poll-url': download_export_instructeur_procedure_path(procedure, export_format: format, no_progress_notification: true) }
= t(:export_pending_html, export_time: time_ago_in_words(export.created_at), export_format: ".#{format}", scope: [:instructeurs, :procedure])
+ %li
+ = link_to t(:download_archive, scope: [:instructeurs, :procedure]), instructeur_archives_path(procedure)
diff --git a/config/locales/views/instructeurs/fr.yml b/config/locales/views/instructeurs/fr.yml
index 3cc5fabdc..17c7ef429 100644
--- a/config/locales/views/instructeurs/fr.yml
+++ b/config/locales/views/instructeurs/fr.yml
@@ -8,3 +8,4 @@ fr:
ods_html: Demander un export au format .ods
export_ready_html: Télécharger l’export au format %{export_format}
(généré il y a %{export_time})
export_pending_html: Un export au format %{export_format} est en train d’être généré
(demandé il y a %{export_time})
+ download_archive: Télécharger une archive au format .zip de tous les dossiers et leurs pièces jointes
diff --git a/config/routes.rb b/config/routes.rb
index bb953ffa4..acdac88ea 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -383,6 +383,8 @@ Rails.application.routes.draw do
get 'telecharger_pjs' => 'dossiers#telecharger_pjs'
end
end
+
+ resources :archives, only: [:index, :create, :show], controller: 'archives'
end
end
get "recherche" => "recherche#index"
diff --git a/spec/controllers/instructeurs/archives_controller_spec.rb b/spec/controllers/instructeurs/archives_controller_spec.rb
new file mode 100644
index 000000000..d698c95bb
--- /dev/null
+++ b/spec/controllers/instructeurs/archives_controller_spec.rb
@@ -0,0 +1,54 @@
+describe Instructeurs::ArchivesController, type: :controller do
+ let(:procedure1) { create(:procedure, :published, groupe_instructeurs: [gi1]) }
+ let(:procedure2) { create(:procedure, :published, groupe_instructeurs: [gi2]) }
+ let!(:instructeur) { create(:instructeur, groupe_instructeurs: [gi1, gi2]) }
+ let!(:archive1) { create(:archive, :generated, groupe_instructeurs: [gi1]) }
+ let!(:archive2) { create(:archive, :generated, groupe_instructeurs: [gi2]) }
+ let(:gi1) { create(:groupe_instructeur) }
+ let(:gi2) { create(:groupe_instructeur) }
+
+ before do
+ sign_in(instructeur.user)
+ end
+
+ after { Timecop.return }
+
+ describe '#index' do
+ before do
+ create_dossier_for_month(procedure1, 2021, 3)
+ create_dossier_for_month(procedure1, 2021, 3)
+ create_dossier_for_month(procedure1, 2021, 2)
+ Timecop.freeze(Time.zone.local(2021, 3, 5))
+ end
+
+ it 'displays archives' do
+ get :index, { params: { procedure_id: procedure1.id } }
+
+ expect(assigns(:dossiers_termines).size).to eq(3)
+ expect(assigns(:archives)).to eq([archive1])
+ end
+ end
+
+ describe '#create' do
+ let(:month) { '21-03' }
+ let(:date_month) { Date.strptime(month, "%Y-%m") }
+ let(:subject) do
+ post :create, {
+ xhr: true,
+ params: { procedure_id: procedure1.id, type: 'monthly', month: month }
+ }
+ end
+
+ it "performs archive creation job" do
+ expect { subject }.to have_enqueued_job(ArchiveCreationJob).with(procedure1, instructeur, 'monthly', date_month)
+ expect(flash.notice).to include("Votre demande a été prise en compte")
+ end
+ end
+
+ private
+
+ def create_dossier_for_month(procedure, year, month)
+ Timecop.freeze(Time.zone.local(year, month, 5))
+ create(:dossier, :accepte, :with_attestation, procedure: procedure)
+ end
+end
diff --git a/spec/views/instructeur/procedures/_download_dossiers.html.haml_spec.rb b/spec/views/instructeur/procedures/_download_dossiers.html.haml_spec.rb
index 45b522742..a796905d9 100644
--- a/spec/views/instructeur/procedures/_download_dossiers.html.haml_spec.rb
+++ b/spec/views/instructeur/procedures/_download_dossiers.html.haml_spec.rb
@@ -16,5 +16,15 @@ describe 'instructeurs/procedures/_download_dossiers.html.haml', type: :view do
context "when procedure has at least 1 dossier en construction" do
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
it { is_expected.to include("Télécharger tous les dossiers") }
+
+ context "With zip archive enabled" do
+ before { Flipper.enable(:archive_zip_globale, procedure) }
+ it { is_expected.to include("Télécharger une archive au format .zip") }
+ end
+
+ context "With zip archive disabled" do
+ before { Flipper.disable(:archive_zip_globale, procedure) }
+ it { is_expected.not_to include("Télécharger une archive au format .zip") }
+ end
end
end