2024-04-29 00:17:15 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-12-03 18:36:50 +01:00
|
|
|
class Export < ApplicationRecord
|
2022-07-07 18:15:48 +02:00
|
|
|
include TransientModelsWithPurgeableJobConcern
|
|
|
|
|
2024-10-14 22:11:25 +02:00
|
|
|
self.ignored_columns += ["procedure_presentation_snapshot"]
|
|
|
|
|
2022-10-17 15:05:14 +02:00
|
|
|
MAX_DUREE_CONSERVATION_EXPORT = 32.hours
|
|
|
|
MAX_DUREE_GENERATION = 16.hours
|
2019-12-03 18:36:50 +01:00
|
|
|
|
|
|
|
enum format: {
|
|
|
|
csv: 'csv',
|
|
|
|
ods: 'ods',
|
2022-04-08 17:12:53 +02:00
|
|
|
xlsx: 'xlsx',
|
2022-11-16 11:50:19 +01:00
|
|
|
zip: 'zip',
|
|
|
|
json: 'json'
|
2022-04-08 17:12:53 +02:00
|
|
|
}, _prefix: true
|
2019-12-03 18:36:50 +01:00
|
|
|
|
2021-06-16 11:46:25 +02:00
|
|
|
enum time_span_type: {
|
|
|
|
everything: 'everything',
|
|
|
|
monthly: 'monthly'
|
|
|
|
}
|
|
|
|
|
2022-04-05 15:53:15 +02:00
|
|
|
enum statut: {
|
|
|
|
'a-suivre': 'a-suivre',
|
|
|
|
suivis: 'suivis',
|
|
|
|
traites: 'traites',
|
|
|
|
tous: 'tous',
|
2024-07-18 14:15:29 +02:00
|
|
|
supprimes: 'supprimes',
|
2022-04-05 15:53:15 +02:00
|
|
|
archives: 'archives',
|
|
|
|
expirant: 'expirant'
|
|
|
|
}
|
|
|
|
|
2019-12-03 18:36:50 +01:00
|
|
|
has_and_belongs_to_many :groupe_instructeurs
|
2022-04-05 15:53:15 +02:00
|
|
|
belongs_to :procedure_presentation, optional: true
|
2023-10-09 09:15:54 +02:00
|
|
|
belongs_to :instructeur, optional: true
|
2024-02-07 17:19:50 +01:00
|
|
|
belongs_to :user_profile, polymorphic: true, optional: true
|
2024-03-08 10:11:11 +01:00
|
|
|
belongs_to :export_template, optional: true
|
2019-12-03 18:36:50 +01:00
|
|
|
|
|
|
|
has_one_attached :file
|
|
|
|
|
2024-10-15 13:30:31 +02:00
|
|
|
attribute :sorted_column, :sorted_column
|
|
|
|
attribute :filtered_columns, :filtered_column, array: true
|
|
|
|
|
2021-03-31 18:19:28 +02:00
|
|
|
validates :format, :groupe_instructeurs, :key, presence: true
|
2019-12-03 18:36:50 +01:00
|
|
|
|
2023-09-21 13:59:14 +02:00
|
|
|
scope :ante_chronological, -> { order(updated_at: :desc) }
|
|
|
|
|
2020-09-29 14:00:31 +02:00
|
|
|
after_create_commit :compute_async
|
2019-12-03 18:36:50 +01:00
|
|
|
|
2022-04-05 15:57:19 +02:00
|
|
|
FORMATS_WITH_TIME_SPAN = [:xlsx, :ods, :csv].flat_map do |format|
|
2022-05-17 17:54:41 +02:00
|
|
|
[{ format: format, time_span_type: 'everything' }]
|
2021-06-16 11:46:25 +02:00
|
|
|
end
|
2022-11-16 11:50:19 +01:00
|
|
|
FORMATS = [:xlsx, :ods, :csv, :zip, :json].map do |format|
|
2022-04-08 17:05:02 +02:00
|
|
|
{ format: format }
|
2022-04-05 15:57:19 +02:00
|
|
|
end
|
2021-06-16 11:46:25 +02:00
|
|
|
|
2019-12-03 18:36:50 +01:00
|
|
|
def compute_async
|
|
|
|
ExportJob.perform_later(self)
|
|
|
|
end
|
|
|
|
|
|
|
|
def compute
|
2023-10-09 10:47:06 +02:00
|
|
|
self.dossiers_count = dossiers_for_export.count
|
2022-04-05 18:11:12 +02:00
|
|
|
|
2023-10-03 11:21:12 +02:00
|
|
|
file.attach(blob.signed_id) # attaching a blob directly might run identify/virus scanner and wipe it
|
2019-12-03 18:36:50 +01:00
|
|
|
end
|
|
|
|
|
2021-06-16 11:46:25 +02:00
|
|
|
def since
|
|
|
|
time_span_type == Export.time_span_types.fetch(:monthly) ? 30.days.ago : nil
|
|
|
|
end
|
|
|
|
|
2024-03-08 17:14:21 +01:00
|
|
|
def self.find_or_create_fresh_export(format, groupe_instructeurs, user_profile, time_span_type: time_span_types.fetch(:everything), statut: statuts.fetch(:tous), procedure_presentation: nil, export_template: nil)
|
2024-10-15 13:30:31 +02:00
|
|
|
filtered_columns = Array.wrap(procedure_presentation&.filters_for(statut))
|
|
|
|
sorted_column = procedure_presentation&.sorted_column
|
|
|
|
|
2023-09-28 12:41:19 +02:00
|
|
|
attributes = {
|
|
|
|
format:,
|
2024-03-08 17:14:21 +01:00
|
|
|
export_template:,
|
2023-09-28 12:41:19 +02:00
|
|
|
time_span_type:,
|
|
|
|
statut:,
|
2024-10-15 10:19:48 +02:00
|
|
|
key: generate_cache_key(groupe_instructeurs.map(&:id), filtered_columns, sorted_column)
|
2023-09-28 12:41:19 +02:00
|
|
|
}
|
2022-11-15 18:53:23 +01:00
|
|
|
|
2023-09-28 12:41:19 +02:00
|
|
|
recent_export = pending
|
|
|
|
.or(generated.where(updated_at: (5.minutes.ago)..))
|
|
|
|
.includes(:procedure_presentation)
|
|
|
|
.find_by(attributes)
|
|
|
|
|
|
|
|
return recent_export if recent_export.present?
|
|
|
|
|
|
|
|
create!(**attributes, groupe_instructeurs:,
|
2024-02-07 17:19:50 +01:00
|
|
|
user_profile:,
|
2024-10-15 13:30:31 +02:00
|
|
|
filtered_columns:,
|
|
|
|
sorted_column:)
|
2019-12-03 18:36:50 +01:00
|
|
|
end
|
|
|
|
|
2023-09-13 12:59:38 +02:00
|
|
|
def self.for_groupe_instructeurs(groupe_instructeurs_ids)
|
2023-09-21 12:13:47 +02:00
|
|
|
joins(:groupe_instructeurs).where(groupe_instructeurs: groupe_instructeurs_ids).distinct(:id)
|
2023-09-11 16:36:55 +02:00
|
|
|
end
|
|
|
|
|
2024-10-14 15:22:05 +02:00
|
|
|
def self.by_key(groupe_instructeurs_ids)
|
|
|
|
where(key: generate_cache_key(groupe_instructeurs_ids))
|
2022-04-05 15:57:19 +02:00
|
|
|
end
|
2021-04-07 09:43:55 +02:00
|
|
|
|
2024-10-15 10:19:48 +02:00
|
|
|
def self.generate_cache_key(groupe_instructeurs_ids, filtered_columns = [], sorted_column = nil)
|
|
|
|
columns_key = ([sorted_column] + filtered_columns).compact.map(&:id).sort.join
|
|
|
|
|
|
|
|
[
|
|
|
|
groupe_instructeurs_ids.sort.join('-'),
|
|
|
|
Digest::MD5.hexdigest(columns_key)
|
|
|
|
].join('--')
|
2021-03-31 18:19:28 +02:00
|
|
|
end
|
|
|
|
|
2022-04-05 15:57:19 +02:00
|
|
|
def count
|
2023-10-09 10:47:06 +02:00
|
|
|
return dossiers_count if !dossiers_count.nil? # export generated
|
2024-10-14 22:23:59 +02:00
|
|
|
return dossiers_for_export.count if built_from_procedure_presentation?
|
2023-10-09 10:47:06 +02:00
|
|
|
|
|
|
|
nil
|
2019-12-03 18:36:50 +01:00
|
|
|
end
|
|
|
|
|
2023-02-08 17:32:40 +01:00
|
|
|
def procedure
|
|
|
|
groupe_instructeurs.first.procedure
|
|
|
|
end
|
|
|
|
|
2024-10-14 22:23:59 +02:00
|
|
|
def built_from_procedure_presentation?
|
|
|
|
sorted_column.present? # hack has we know that procedure_presentation always has a sorted_column
|
|
|
|
end
|
|
|
|
|
2019-12-03 18:36:50 +01:00
|
|
|
private
|
|
|
|
|
2022-04-05 15:57:19 +02:00
|
|
|
def dossiers_for_export
|
|
|
|
@dossiers_for_export ||= begin
|
|
|
|
dossiers = Dossier.where(groupe_instructeur: groupe_instructeurs)
|
|
|
|
|
|
|
|
if since.present?
|
|
|
|
dossiers.visible_by_administration.where('dossiers.depose_at > ?', since)
|
2024-10-15 13:30:31 +02:00
|
|
|
elsif filtered_columns.present? || sorted_column.present?
|
2024-10-15 13:28:44 +02:00
|
|
|
instructeur = instructeur_from(user_profile)
|
|
|
|
filtered_sorted_ids = DossierFilterService.filtered_sorted_ids(dossiers, statut, filtered_columns, sorted_column, instructeur)
|
2022-04-05 15:57:19 +02:00
|
|
|
|
|
|
|
dossiers.where(id: filtered_sorted_ids)
|
|
|
|
else
|
2022-05-10 14:38:04 +02:00
|
|
|
dossiers.visible_by_administration
|
2022-04-05 15:57:19 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-10-15 13:28:44 +02:00
|
|
|
def instructeur_from(user_profile)
|
|
|
|
case user_profile
|
|
|
|
when Administrateur
|
|
|
|
user_profile.instructeur
|
|
|
|
when Instructeur
|
|
|
|
user_profile
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-04-08 17:12:34 +02:00
|
|
|
def blob
|
2024-03-08 17:14:21 +01:00
|
|
|
service = ProcedureExportService.new(procedure, dossiers_for_export, user_profile, export_template)
|
2019-12-03 18:36:50 +01:00
|
|
|
|
|
|
|
case format.to_sym
|
|
|
|
when :csv
|
2022-04-08 17:12:34 +02:00
|
|
|
service.to_csv
|
2019-12-03 18:36:50 +01:00
|
|
|
when :xlsx
|
2022-04-08 17:12:34 +02:00
|
|
|
service.to_xlsx
|
2019-12-03 18:36:50 +01:00
|
|
|
when :ods
|
2022-04-08 17:12:34 +02:00
|
|
|
service.to_ods
|
2022-04-08 17:12:53 +02:00
|
|
|
when :zip
|
|
|
|
service.to_zip
|
2022-11-16 11:50:19 +01:00
|
|
|
when :json
|
|
|
|
service.to_geo_json
|
2019-12-03 18:36:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|