Merge pull request #7120 from betagouv/main

2022-04-05-01
This commit is contained in:
mfo 2022-04-05 14:11:15 +02:00 committed by GitHub
commit 39a40c43e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 212 additions and 214 deletions

View file

@ -139,8 +139,6 @@ module Experts
end end
def telecharger_pjs def telecharger_pjs
return head(:forbidden) if !avis.dossier.export_and_attachments_downloadable?
files = ActiveStorage::DownloadableFile.create_list_from_dossier(@dossier, true) files = ActiveStorage::DownloadableFile.create_list_from_dossier(@dossier, true)
zipline(files, "dossier-#{@dossier.id}.zip") zipline(files, "dossier-#{@dossier.id}.zip")

View file

@ -218,8 +218,6 @@ module Instructeurs
end end
def telecharger_pjs def telecharger_pjs
return head(:forbidden) if !dossier.export_and_attachments_downloadable?
files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier) files = ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
zipline(files, "dossier-#{dossier.id}.zip") zipline(files, "dossier-#{dossier.id}.zip")

View file

@ -12,7 +12,9 @@ module Instructeurs
.includes(:defaut_groupe_instructeur) .includes(:defaut_groupe_instructeur)
.order(closed_at: :desc, unpublished_at: :desc, published_at: :desc, created_at: :desc) .order(closed_at: :desc, unpublished_at: :desc, published_at: :desc, created_at: :desc)
dossiers = current_instructeur.dossiers.joins(:groupe_instructeur) dossiers = current_instructeur.dossiers
.joins(groupe_instructeur: :procedure)
.where(procedures: { hidden_at: nil })
dossiers_visibles = dossiers.visible_by_administration dossiers_visibles = dossiers.visible_by_administration
@dossiers_count_per_procedure = dossiers_visibles.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_count_per_procedure = dossiers_visibles.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count
@dossiers_a_suivre_count_per_procedure = dossiers_visibles.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count @dossiers_a_suivre_count_per_procedure = dossiers_visibles.without_followers.en_cours.group('groupe_instructeurs.procedure_id').reorder(nil).count
@ -61,47 +63,29 @@ module Instructeurs
@can_download_dossiers = (@tous_count + @archives_count) > 0 @can_download_dossiers = (@tous_count + @archives_count) > 0
dossiers = Dossier.where(groupe_instructeur_id: groupe_instructeur_ids) dossiers = Dossier.where(groupe_instructeur_id: groupe_instructeur_ids)
dossiers_visibles = dossiers.visible_by_administration
@a_suivre_dossiers = dossiers_visibles @followed_dossiers_id = current_instructeur
.without_followers
.en_cours
@followed_dossiers = current_instructeur
.followed_dossiers .followed_dossiers
.en_cours .en_cours
.merge(dossiers_visibles) .merge(dossiers.visible_by_administration)
.pluck(:id)
@followed_dossiers_id = @followed_dossiers.pluck(:id) @dossiers = dossiers.by_statut(current_instructeur, statut)
dossiers_count = case statut
@termines_dossiers = dossiers_visibles.termine
@all_state_dossiers = dossiers_visibles.all_state
@archived_dossiers = dossiers_visibles.archived
@expirant_dossiers = dossiers_visibles.termine_or_en_construction_close_to_expiration
@supprimes_recemment_dossiers = dossiers.hidden_by_administration.termine
@dossiers = case statut
when 'a-suivre' when 'a-suivre'
dossiers_count = @a_suivre_count @a_suivre_count
@a_suivre_dossiers
when 'suivis' when 'suivis'
dossiers_count = @suivis_count @suivis_count
@followed_dossiers
when 'traites' when 'traites'
dossiers_count = @traites_count @traites_count
@termines_dossiers
when 'tous' when 'tous'
dossiers_count = @tous_count @tous_count
@all_state_dossiers
when 'supprimes_recemment' when 'supprimes_recemment'
dossiers_count = @supprimes_recemment_count @supprimes_recemment_count
@supprimes_recemment_dossiers
when 'archives' when 'archives'
dossiers_count = @archives_count @archives_count
@archived_dossiers
when 'expirant' when 'expirant'
dossiers_count = @expirant_count @expirant_count
@expirant_dossiers
end end
notifications = current_instructeur.notifications_for_groupe_instructeurs(groupe_instructeur_ids) notifications = current_instructeur.notifications_for_groupe_instructeurs(groupe_instructeur_ids)
@ -109,7 +93,7 @@ module Instructeurs
@has_termine_notifications = notifications[:termines].present? @has_termine_notifications = notifications[:termines].present?
@not_archived_notifications_dossier_ids = notifications[:en_cours] + notifications[:termines] @not_archived_notifications_dossier_ids = notifications[:en_cours] + notifications[:termines]
sorted_ids = procedure_presentation.sorted_ids(@dossiers, dossiers_count, current_instructeur) sorted_ids = procedure_presentation.sorted_ids(@dossiers, dossiers_count)
if @current_filters.count > 0 if @current_filters.count > 0
filtered_ids = procedure_presentation.filtered_ids(@dossiers, statut) filtered_ids = procedure_presentation.filtered_ids(@dossiers, statut)

View file

@ -11,6 +11,12 @@ class ActiveStorage::DownloadableFile
end end
end end
def self.create_list_from_dossiers(dossiers)
dossiers.flat_map do |dossier|
create_list_from_dossier(dossier)
end
end
private private
def self.timestamped_filename(attachment) def self.timestamped_filename(attachment)

View file

@ -56,8 +56,6 @@ class Dossier < ApplicationRecord
INSTRUCTION_COMMENCEE = TERMINE + [states.fetch(:en_instruction)] INSTRUCTION_COMMENCEE = TERMINE + [states.fetch(:en_instruction)]
SOUMIS = EN_CONSTRUCTION_OU_INSTRUCTION + TERMINE SOUMIS = EN_CONSTRUCTION_OU_INSTRUCTION + TERMINE
TAILLE_MAX_ZIP = 100.megabytes
REMAINING_DAYS_BEFORE_CLOSING = 2 REMAINING_DAYS_BEFORE_CLOSING = 2
INTERVAL_BEFORE_CLOSING = "#{REMAINING_DAYS_BEFORE_CLOSING} days" INTERVAL_BEFORE_CLOSING = "#{REMAINING_DAYS_BEFORE_CLOSING} days"
REMAINING_WEEKS_BEFORE_EXPIRATION = 2 REMAINING_WEEKS_BEFORE_EXPIRATION = 2
@ -235,10 +233,11 @@ class Dossier < ApplicationRecord
scope :en_instruction, -> { not_archived.state_en_instruction } scope :en_instruction, -> { not_archived.state_en_instruction }
scope :termine, -> { not_archived.state_termine } scope :termine, -> { not_archived.state_termine }
scope :processed_in_month, -> (month) do scope :processed_in_month, -> (date) do
date = date.to_datetime
state_termine state_termine
.joins(:traitements) .joins(:traitements)
.where(traitements: { processed_at: month.beginning_of_month..month.end_of_month }) .where(traitements: { processed_at: date.beginning_of_month..date.end_of_month })
end end
scope :downloadable_sorted, -> { scope :downloadable_sorted, -> {
state_not_brouillon state_not_brouillon
@ -301,18 +300,18 @@ class Dossier < ApplicationRecord
scope :interval_brouillon_close_to_expiration, -> do scope :interval_brouillon_close_to_expiration, -> do
state_brouillon state_brouillon
.visible_by_user .visible_by_user
.where("dossiers.created_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 }) .where("dossiers.created_at + dossiers.conservation_extension + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
end end
scope :interval_en_construction_close_to_expiration, -> do scope :interval_en_construction_close_to_expiration, -> do
state_en_construction state_en_construction
.visible_by_user_or_administration .visible_by_user_or_administration
.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 }) .where("dossiers.en_construction_at + dossiers.conservation_extension + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
end end
scope :interval_termine_close_to_expiration, -> do scope :interval_termine_close_to_expiration, -> do
state_termine state_termine
.visible_by_user_or_administration .visible_by_user_or_administration
.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 }) .where("dossiers.processed_at + dossiers.conservation_extension + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
end end
scope :brouillon_close_to_expiration, -> do scope :brouillon_close_to_expiration, -> do
@ -395,6 +394,30 @@ class Dossier < ApplicationRecord
.distinct .distinct
end end
scope :by_statut, -> (instructeur, statut = 'tous') do
case statut
when 'a-suivre'
visible_by_administration
.without_followers
.en_cours
when 'suivis'
instructeur
.followed_dossiers
.en_cours
.merge(visible_by_administration)
when 'traites'
visible_by_administration.termine
when 'tous'
visible_by_administration.all_state
when 'supprimes_recemment'
hidden_by_administration.termine
when 'archives'
visible_by_administration.archived
when 'expirant'
visible_by_administration.termine_or_en_construction_close_to_expiration
end
end
accepts_nested_attributes_for :individual accepts_nested_attributes_for :individual
delegate :siret, :siren, to: :etablissement, allow_nil: true delegate :siret, :siren, to: :etablissement, allow_nil: true
@ -1084,10 +1107,6 @@ class Dossier < ApplicationRecord
end end
end end
def export_and_attachments_downloadable?
PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
end
def linked_dossiers_for(instructeur_or_expert) def linked_dossiers_for(instructeur_or_expert)
dossier_ids = champs.filter(&:dossier_link?).filter_map(&:value) dossier_ids = champs.filter(&:dossier_link?).filter_map(&:value)
instructeur_or_expert.dossiers.where(id: dossier_ids) instructeur_or_expert.dossiers.where(id: dossier_ids)

View file

@ -110,7 +110,11 @@ class Instructeur < ApplicationRecord
end end
def procedure_presentation_and_errors_for_procedure_id(procedure_id) def procedure_presentation_and_errors_for_procedure_id(procedure_id)
assign_to.joins(:groupe_instructeur).find_by(groupe_instructeurs: { procedure_id: procedure_id }).procedure_presentation_or_default_and_errors assign_to
.joins(:groupe_instructeur)
.includes(:instructeur, :procedure)
.find_by(groupe_instructeurs: { procedure_id: procedure_id })
.procedure_presentation_or_default_and_errors
end end
def notifications_for_dossier(dossier) def notifications_for_dossier(dossier)

View file

@ -513,27 +513,6 @@ class Procedure < ApplicationRecord
self.dossiers.state_not_brouillon.size self.dossiers.state_not_brouillon.size
end end
def export_filename(format)
procedure_identifier = path || "procedure-#{id}"
"dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
end
def export(dossiers)
ProcedureExportService.new(self, dossiers)
end
def to_csv(dossiers)
export(dossiers).to_csv
end
def to_xlsx(dossiers)
export(dossiers).to_xlsx
end
def to_ods(dossiers)
export(dossiers).to_ods
end
def procedure_overview(start_date, groups) def procedure_overview(start_date, groups)
ProcedureOverview.new(self, start_date, groups) ProcedureOverview.new(self, start_date, groups)
end end

View file

@ -25,8 +25,7 @@ class ProcedurePresentation < ApplicationRecord
FILTERS_VALUE_MAX_LENGTH = 100 FILTERS_VALUE_MAX_LENGTH = 100
belongs_to :assign_to, optional: false belongs_to :assign_to, optional: false
delegate :procedure, :instructeur, to: :assign_to
delegate :procedure, to: :assign_to
validate :check_allowed_displayed_fields validate :check_allowed_displayed_fields
validate :check_allowed_sort_column validate :check_allowed_sort_column
@ -84,7 +83,7 @@ class ProcedurePresentation < ApplicationRecord
] ]
end end
def sorted_ids(dossiers, count, instructeur) def sorted_ids(dossiers, count)
table, column, order = sort.values_at(TABLE, COLUMN, 'order') table, column, order = sort.values_at(TABLE, COLUMN, 'order')
case table case table

View file

@ -4,19 +4,7 @@ class PiecesJustificativesService
pjs_commentaires = pjs_for_commentaires(dossier) pjs_commentaires = pjs_for_commentaires(dossier)
pjs_dossier = pjs_for_dossier(dossier, for_expert) pjs_dossier = pjs_for_dossier(dossier, for_expert)
pjs_champs + pjs_commentaires + pjs_dossier.filter(&:attached?) pjs_champs + pjs_commentaires + pjs_dossier
end
def self.liste_pieces_justificatives(dossier)
pjs_champs = pjs_for_champs(dossier)
pjs_commentaires = pjs_for_commentaires(dossier)
pjs_champs + pjs_commentaires
end
def self.pieces_justificatives_total_size(dossier)
liste_pieces_justificatives(dossier)
.sum(&:byte_size)
end end
def self.serialize_types_de_champ_as_type_pj(revision) def self.serialize_types_de_champ_as_type_pj(revision)
@ -143,21 +131,57 @@ class PiecesJustificativesService
end end
def self.pjs_for_dossier(dossier, for_expert = false) def self.pjs_for_dossier(dossier, for_expert = false)
pjs = [ pjs = motivation(dossier) +
dossier.justificatif_motivation, attestation(dossier) +
dossier.attestation&.pdf, etablissement(dossier)
dossier.etablissement&.entreprise_attestation_sociale,
dossier.etablissement&.entreprise_attestation_fiscale
].flatten.compact
if !for_expert if !for_expert
bill_signatures = dossier.dossier_operation_logs.filter_map(&:bill_signature).uniq pjs += operation_logs_and_signatures(dossier)
pjs += [
dossier.dossier_operation_logs.map(&:serialized),
bill_signatures.map(&:serialized),
bill_signatures.map(&:signature)
].flatten.compact
end end
pjs pjs
end end
def self.etablissement(dossier)
etablissement = Etablissement.where(dossier: dossier)
ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "Etablissement", record_id: etablissement)
end
def self.motivation(dossier)
ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "Dossier", name: "justificatif_motivation", record_id: dossier)
end
def self.attestation(dossier)
attestation = Attestation
.joins(:pdf_attachment)
.where(dossier: dossier)
ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "Attestation", record_id: attestation)
end
def self.operation_logs_and_signatures(dossier)
dol_ids_bill_id = DossierOperationLog
.where(dossier: dossier)
.pluck(:id, :bill_signature_id)
dol_ids = dol_ids_bill_id.map(&:first)
bill_ids = dol_ids_bill_id.map(&:second).uniq.compact
serialized_dols = ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "DossierOperationLog", record_id: dol_ids)
bill_docs = ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "BillSignature", record_id: bill_ids)
serialized_dols + bill_docs
end
end end

View file

@ -25,7 +25,8 @@ class ProcedureArchiveService
dossiers.processed_in_month(archive.month) dossiers.processed_in_month(archive.month)
end end
attachments = create_list_of_attachments(dossiers) attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers)
download_and_zip(archive, attachments) do |zip_filepath| download_and_zip(archive, attachments) do |zip_filepath|
ArchiveUploader.new(procedure: @procedure, archive: archive, filepath: zip_filepath) ArchiveUploader.new(procedure: @procedure, archive: archive, filepath: zip_filepath)
.upload .upload
@ -72,12 +73,6 @@ class ProcedureArchiveService
"procedure-#{@procedure.id}-#{archive.id}" "procedure-#{@procedure.id}-#{archive.id}"
end end
def create_list_of_attachments(dossiers)
dossiers.flat_map do |dossier|
ActiveStorage::DownloadableFile.create_list_from_dossier(dossier)
end
end
def self.attachments_from_champs_piece_justificative(champs) def self.attachments_from_champs_piece_justificative(champs)
champs champs
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) } .filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) }

View file

@ -9,11 +9,7 @@
%button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' } %button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' }
%span.icon.attached %span.icon.attached
%ul#print-pj-menu.print-menu.dropdown-content %ul#print-pj-menu.print-menu.dropdown-content
%li %li= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_expert_avis_path(avis), target: "_blank", rel: "noopener", class: "menu-item menu-link"
- if dossier.export_and_attachments_downloadable?
= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_expert_avis_path(avis), target: "_blank", rel: "noopener", class: "menu-item menu-link"
- else
%p.menu-item Le téléchargement des pièces jointes est désactivé pour les dossiers de plus de #{number_to_human_size Dossier::TAILLE_MAX_ZIP}.
%nav.tabs %nav.tabs
%ul %ul

View file

@ -16,11 +16,7 @@
%button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' } %button.button.dropdown-button.icon-only{ 'aria-expanded' => 'false', 'aria-controls' => 'print-pj-menu' }
%span.icon.attached %span.icon.attached
%ul#print-pj-menu.print-menu.dropdown-content %ul#print-pj-menu.print-menu.dropdown-content
%li %li= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
- if dossier.export_and_attachments_downloadable?
= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
- else
%p.menu-item Le téléchargement des pièces jointes est désactivé pour les dossiers de plus de #{number_to_human_size Dossier::TAILLE_MAX_ZIP}.
= render partial: "instructeurs/procedures/dossier_actions", = render partial: "instructeurs/procedures/dossier_actions",
locals: { procedure_id: dossier.procedure.id, locals: { procedure_id: dossier.procedure.id,

View file

@ -0,0 +1,25 @@
namespace :after_party do
desc 'Deployment task: remove_duplicate_attestations'
task remove_duplicate_attestations: :environment do
dossier_ids = Attestation
.group(:dossier_id)
.count
.filter { |_, attestation_count| attestation_count > 1 }
.map(&:first)
dossier_ids.each do |dossier_id|
current_attestation, *old_attestations = Attestation.where(dossier_id: dossier_id).order(created_at: :desc)
old_attestations.each do |old|
if current_attestation.created_at < old.created_at
raise "something odd, old attestation #{old.id} is newer than the current attestation #{current_attestation.id}"
end
old.destroy
end
end
AfterParty::TaskRecord
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
end
end

View file

@ -155,6 +155,23 @@ describe Instructeurs::ProceduresController, type: :controller do
it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(1 + 0) } it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(1 + 0) }
it { expect(assigns(:all_dossiers_counts)['expirant']).to eq(2 + 0) } it { expect(assigns(:all_dossiers_counts)['expirant']).to eq(2 + 0) }
end end
context 'with not draft state on discarded procedure' do
let(:discarded_procedure) { create(:procedure, :discarded, :expirable) }
let(:state) { Dossier.states.fetch(:en_construction) }
before do
create(:dossier, procedure: discarded_procedure, state: Dossier.states.fetch(:en_construction))
instructeur.groupe_instructeurs << discarded_procedure.defaut_groupe_instructeur
subject
end
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(1) }
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(1) }
it { expect(assigns(:dossiers_count_per_procedure)[discarded_procedure.id]).to be_nil }
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(1) }
end
end end
context "with a routed procedure" do context "with a routed procedure" do
@ -257,38 +274,34 @@ describe Instructeurs::ProceduresController, type: :controller do
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) } let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
before { subject } before { subject }
it { expect(assigns(:a_suivre_dossiers)).to match_array([new_unfollow_dossier]) } it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier]) }
it { expect(assigns(:followed_dossiers)).to be_empty }
it { expect(assigns(:termines_dossiers)).to be_empty }
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier]) }
it { expect(assigns(:archived_dossiers)).to be_empty }
context 'with a dossier en contruction hidden by user' do context 'with a dossier en contruction hidden by user' do
let!(:hidden_dossier) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_construction), hidden_by_user_at: 1.hour.ago) } let!(:hidden_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2, hidden_by_user_at: 1.hour.ago) }
before { subject } before { subject }
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier]) } it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier]) }
end end
context 'with a dossier en contruction not hidden by user' do context 'with a dossier en contruction not hidden by user' do
let!(:en_construction_dossier) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_construction)) } let!(:en_construction_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2) }
before { subject } before { subject }
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier, en_construction_dossier]) } it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier, en_construction_dossier]) }
end end
context 'and dossiers without follower on each of the others groups' do context 'and dossiers without follower on each of the others groups' do
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction)) } let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction)) } let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
before { subject } before { subject }
it { expect(assigns(:a_suivre_dossiers)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2]) } it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2]) }
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2]) }
end end
end end
context 'with a new dossier with a follower' do context 'with a new dossier with a follower' do
let(:statut) { 'suivis' }
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure) } let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
before do before do
@ -296,15 +309,11 @@ describe Instructeurs::ProceduresController, type: :controller do
subject subject
end end
it { expect(assigns(:a_suivre_dossiers)).to be_empty } it { expect(assigns(:dossiers)).to match_array([new_followed_dossier]) }
it { expect(assigns(:followed_dossiers)).to match_array([new_followed_dossier]) }
it { expect(assigns(:termines_dossiers)).to be_empty }
it { expect(assigns(:all_state_dossiers)).to match_array([new_followed_dossier]) }
it { expect(assigns(:archived_dossiers)).to be_empty }
context 'and dossier with a follower on each of the others groups' do context 'and dossier with a follower on each of the others groups' do
let!(:new_follow_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction)) } let!(:new_follow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
let!(:new_follow_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction)) } let!(:new_follow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
before do before do
instructeur.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3 instructeur.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3
@ -312,44 +321,36 @@ describe Instructeurs::ProceduresController, type: :controller do
end end
# followed dossiers on another groupe should not be displayed # followed dossiers on another groupe should not be displayed
it { expect(assigns(:followed_dossiers)).to contain_exactly(new_followed_dossier, new_follow_dossier_on_gi_2) } it { expect(assigns(:dossiers)).to contain_exactly(new_followed_dossier, new_follow_dossier_on_gi_2) }
it { expect(assigns(:all_state_dossiers)).to contain_exactly(new_followed_dossier, new_follow_dossier_on_gi_2) }
end end
end end
context 'with a termine dossier with a follower' do context 'with a termine dossier with a follower' do
let(:statut) { 'traites' }
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) } let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) }
before { subject } before { subject }
it { expect(assigns(:a_suivre_dossiers)).to be_empty } it { expect(assigns(:dossiers)).to match_array([termine_dossier]) }
it { expect(assigns(:followed_dossiers)).to be_empty }
it { expect(assigns(:termines_dossiers)).to match_array([termine_dossier]) }
it { expect(assigns(:all_state_dossiers)).to match_array([termine_dossier]) }
it { expect(assigns(:archived_dossiers)).to be_empty }
context 'and terminer dossiers on each of the others groups' do context 'and terminer dossiers on each of the others groups' do
let!(:termine_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:accepte)) } let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) }
let!(:termine_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:accepte)) } let!(:termine_dossier_on_gi_3) { create(:dossier, :accepte, groupe_instructeur: gi_3) }
before { subject } before { subject }
it { expect(assigns(:termines_dossiers)).to match_array([termine_dossier, termine_dossier_on_gi_2]) } it { expect(assigns(:dossiers)).to match_array([termine_dossier, termine_dossier_on_gi_2]) }
it { expect(assigns(:all_state_dossiers)).to match_array([termine_dossier, termine_dossier_on_gi_2]) }
end end
end end
context 'with an archived dossier' do context 'with an archived dossier' do
let(:statut) { 'archives' }
let!(:archived_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) } let!(:archived_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) }
let!(:archived_dossier_deleted) { create(:dossier, :en_instruction, procedure: procedure, archived: true, hidden_by_administration_at: 2.days.ago) } let!(:archived_dossier_deleted) { create(:dossier, :en_instruction, procedure: procedure, archived: true, hidden_by_administration_at: 2.days.ago) }
before { subject } before { subject }
it { expect(assigns(:a_suivre_dossiers)).to be_empty } it { expect(assigns(:dossiers)).to match_array([archived_dossier]) }
it { expect(assigns(:followed_dossiers)).to be_empty }
it { expect(assigns(:termines_dossiers)).to be_empty }
it { expect(assigns(:all_state_dossiers)).to be_empty }
it { expect(assigns(:archived_dossiers)).to match_array([archived_dossier]) }
context 'and terminer dossiers on each of the others groups' do context 'and terminer dossiers on each of the others groups' do
let!(:archived_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) } let!(:archived_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) }
@ -357,22 +358,23 @@ describe Instructeurs::ProceduresController, type: :controller do
before { subject } before { subject }
it { expect(assigns(:archived_dossiers)).to match_array([archived_dossier, archived_dossier_on_gi_2]) } it { expect(assigns(:dossiers)).to match_array([archived_dossier, archived_dossier_on_gi_2]) }
end end
end end
context 'with an expirants dossier' do context 'with an expirants dossier' do
let(:statut) { 'expirant' }
let!(:expiring_dossier_termine_deleted) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago, hidden_by_administration_at: 2.days.ago) } let!(:expiring_dossier_termine_deleted) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago, hidden_by_administration_at: 2.days.ago) }
let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) } let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) }
let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 175.days.ago) } let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 175.days.ago) }
before { subject } before { subject }
it { expect(assigns(:expirant_dossiers)).to match_array([expiring_dossier_termine, expiring_dossier_en_construction]) } it { expect(assigns(:dossiers)).to match_array([expiring_dossier_termine, expiring_dossier_en_construction]) }
end end
describe 'statut' do describe 'statut' do
let!(:a_suivre__dossier) { Timecop.freeze(1.day.ago) { create(:dossier, :en_instruction, procedure: procedure) } } let!(:a_suivre_dossier) { Timecop.freeze(1.day.ago) { create(:dossier, :en_instruction, procedure: procedure) } }
let!(:new_followed_dossier) { Timecop.freeze(2.days.ago) { create(:dossier, :en_instruction, procedure: procedure) } } let!(:new_followed_dossier) { Timecop.freeze(2.days.ago) { create(:dossier, :en_instruction, procedure: procedure) } }
let!(:termine_dossier) { Timecop.freeze(3.days.ago) { create(:dossier, :accepte, procedure: procedure) } } let!(:termine_dossier) { Timecop.freeze(3.days.ago) { create(:dossier, :accepte, procedure: procedure) } }
let!(:archived_dossier) { Timecop.freeze(4.days.ago) { create(:dossier, :en_instruction, procedure: procedure, archived: true) } } let!(:archived_dossier) { Timecop.freeze(4.days.ago) { create(:dossier, :en_instruction, procedure: procedure, archived: true) } }
@ -385,7 +387,7 @@ describe Instructeurs::ProceduresController, type: :controller do
context 'when statut is empty' do context 'when statut is empty' do
let(:statut) { nil } let(:statut) { nil }
it { expect(assigns(:dossiers)).to match_array([a_suivre__dossier]) } it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier]) }
it { expect(assigns(:statut)).to eq('a-suivre') } it { expect(assigns(:statut)).to eq('a-suivre') }
end end
@ -393,7 +395,7 @@ describe Instructeurs::ProceduresController, type: :controller do
let(:statut) { 'a-suivre' } let(:statut) { 'a-suivre' }
it { expect(assigns(:statut)).to eq('a-suivre') } it { expect(assigns(:statut)).to eq('a-suivre') }
it { expect(assigns(:dossiers)).to match_array([a_suivre__dossier]) } it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier]) }
end end
context 'when statut is suivis' do context 'when statut is suivis' do
@ -414,7 +416,7 @@ describe Instructeurs::ProceduresController, type: :controller do
let(:statut) { 'tous' } let(:statut) { 'tous' }
it { expect(assigns(:statut)).to eq('tous') } it { expect(assigns(:statut)).to eq('tous') }
it { expect(assigns(:dossiers)).to match_array([a_suivre__dossier, new_followed_dossier, termine_dossier]) } it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier, new_followed_dossier, termine_dossier]) }
end end
context 'when statut is archives' do context 'when statut is archives' do
@ -465,7 +467,7 @@ describe Instructeurs::ProceduresController, type: :controller do
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
let!(:procedure) { create(:procedure) } let!(:procedure) { create(:procedure) }
let!(:gi_0) { procedure.defaut_groupe_instructeur } let!(:gi_0) { procedure.defaut_groupe_instructeur }
let!(:gi_1) { GroupeInstructeur.create(label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) } let!(:gi_1) { create(:groupe_instructeur, label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) }
before { sign_in(instructeur.user) } before { sign_in(instructeur.user) }
@ -494,7 +496,7 @@ describe Instructeurs::ProceduresController, type: :controller do
end end
context 'when the export is ready' do context 'when the export is ready' do
let!(:export) { create(:export, groupe_instructeurs: [gi_1]) } let(:export) { create(:export, groupe_instructeurs: [gi_1]) }
before do before do
export.file.attach(io: StringIO.new('export'), filename: 'file.csv') export.file.attach(io: StringIO.new('export'), filename: 'file.csv')
@ -507,7 +509,7 @@ describe Instructeurs::ProceduresController, type: :controller do
end end
context 'when another export is ready' do context 'when another export is ready' do
let!(:export) { create(:export, groupe_instructeurs: [gi_0, gi_1]) } let(:export) { create(:export, groupe_instructeurs: [gi_0, gi_1]) }
before do before do
export.file.attach(io: StringIO.new('export'), filename: 'file.csv') export.file.attach(io: StringIO.new('export'), filename: 'file.csv')

View file

@ -1190,30 +1190,6 @@ describe Dossier do
after { Timecop.return } after { Timecop.return }
end end
describe '#export_and_attachments_downloadable?' do
let(:dossier) { create(:dossier, user: user) }
context "no attachments" do
it {
expect(dossier.export_and_attachments_downloadable?).to be true
}
end
context "with a small attachment" do
it {
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(4.megabytes)
expect(dossier.export_and_attachments_downloadable?).to be true
}
end
context "with a too large attachment" do
it {
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(100.megabytes)
expect(dossier.export_and_attachments_downloadable?).to be false
}
end
end
describe '#notify_draft_not_submitted' do describe '#notify_draft_not_submitted' do
let!(:user1) { create(:user) } let!(:user1) { create(:user) }
let!(:user2) { create(:user) } let!(:user2) { create(:user) }
@ -1744,4 +1720,29 @@ describe Dossier do
expect(rebased_datetime_champ.rebased_at).not_to be_nil expect(rebased_datetime_champ.rebased_at).not_to be_nil
end end
end end
describe '#processed_in_month' do
include ActiveSupport::Testing::TimeHelpers
let(:dossier_accepte_at) { DateTime.new(2022, 3, 31, 12, 0) }
before do
travel_to(dossier_accepte_at) do
dossier = create(:dossier, :accepte)
end
end
context 'given a date' do
let(:archive_date) { Date.new(2022, 3, 1) }
it 'includes a dossier processed_at at last day of month' do
expect(Dossier.processed_in_month(archive_date).count).to eq(1)
end
end
context 'given a datetime' do
let(:archive_date) { DateTime.new(2022, 3, 1, 12, 0) }
it 'includes a dossier processed_at at last day of month' do
expect(Dossier.processed_in_month(archive_date).count).to eq(1)
end
end
end
end end

View file

@ -133,7 +133,7 @@ describe ProcedurePresentation do
let(:sort) { { 'table' => table, 'column' => column, 'order' => order } } let(:sort) { { 'table' => table, 'column' => column, 'order' => order } }
let(:procedure_presentation) { create(:procedure_presentation, assign_to: assign_to, sort: sort) } let(:procedure_presentation) { create(:procedure_presentation, assign_to: assign_to, sort: sort) }
subject { procedure_presentation.sorted_ids(procedure.dossiers, procedure.dossiers.count, instructeur) } subject { procedure_presentation.sorted_ids(procedure.dossiers, procedure.dossiers.count) }
context 'for notifications table' do context 'for notifications table' do
let(:table) { 'notifications' } let(:table) { 'notifications' }

View file

@ -1059,17 +1059,6 @@ describe Procedure do
it { expect(Procedure.default_sort).to eq({ "table" => "self", "column" => "id", "order" => "desc" }) } it { expect(Procedure.default_sort).to eq({ "table" => "self", "column" => "id", "order" => "desc" }) }
end end
describe "#export_filename" do
before { Timecop.freeze(Time.zone.local(2018, 1, 2, 23, 11, 14)) }
after { Timecop.return }
subject { procedure.export_filename(:csv) }
let(:procedure) { create(:procedure, :published) }
it { is_expected.to eq("dossiers_#{procedure.path}_2018-01-02_23-11.csv") }
end
describe '#new_dossier' do describe '#new_dossier' do
let(:procedure) do let(:procedure) do
create(:procedure, create(:procedure,

View file

@ -15,23 +15,6 @@ describe PiecesJustificativesService do
create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature) create(:dossier_operation_log, dossier: dossier, bill_signature: bill_signature)
end end
describe '.liste_pieces_justificatives' do
subject { PiecesJustificativesService.liste_pieces_justificatives(dossier) }
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
end
it "doesn't return export pdf of the dossier" do
expect(subject.any? { |piece| piece.name == 'pdf_export_for_instructeur' }).to be_falsy
end
it "doesn't return operation logs of the dossier" do
expect(subject.any? { |piece| piece.name == 'serialized' }).to be_falsy
end
end
describe '.liste_documents' do describe '.liste_documents' do
subject { PiecesJustificativesService.liste_documents(dossier, false) } subject { PiecesJustificativesService.liste_documents(dossier, false) }

View file

@ -44,7 +44,7 @@ describe ProcedureArchiveService do
let(:year) { 2021 } let(:year) { 2021 }
it 'collects files with success' do it 'collects files with success' do
allow_any_instance_of(ActiveStorage::Attached::One).to receive(:url).and_return("https://opengraph.githubassets.com/d0e7862b24d8026a3c03516d865b28151eb3859029c6c6c2e86605891fbdcd7a/socketry/async-io") allow_any_instance_of(ActiveStorage::Attachment).to receive(:url).and_return("https://opengraph.githubassets.com/d0e7862b24d8026a3c03516d865b28151eb3859029c6c6c2e86605891fbdcd7a/socketry/async-io")
VCR.use_cassette('archive/new_file_to_get_200') do VCR.use_cassette('archive/new_file_to_get_200') do
service.make_and_upload_archive(archive, instructeur) service.make_and_upload_archive(archive, instructeur)
@ -145,7 +145,7 @@ describe ProcedureArchiveService do
let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending', groupe_instructeurs: groupe_instructeurs) } let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending', groupe_instructeurs: groupe_instructeurs) }
it 'collect files' do it 'collect files' do
allow_any_instance_of(ActiveStorage::Attached::One).to receive(:url).and_return("https://opengraph.githubassets.com/5e61989aecb78e369c93674f877d7bf4ecde378850114a9563cdf8b6a2472536/typhoeus/typhoeus/issues/110") allow_any_instance_of(ActiveStorage::Attachment).to receive(:url).and_return("https://opengraph.githubassets.com/5e61989aecb78e369c93674f877d7bf4ecde378850114a9563cdf8b6a2472536/typhoeus/typhoeus/issues/110")
VCR.use_cassette('archive/old_file_to_get_200') do VCR.use_cassette('archive/old_file_to_get_200') do
service.make_and_upload_archive(archive, instructeur) service.make_and_upload_archive(archive, instructeur)