demarches-normaliennes/app/services/dossier_projection_service.rb

153 lines
7 KiB
Ruby
Raw Normal View History

2021-04-21 12:02:57 +02:00
class DossierProjectionService
2023-12-11 17:06:12 +01:00
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :hidden_by_administration_at, :for_tiers, :prenom, :nom, :batch_operation_id, :sva_svr_decision_on, :corrections, :columns) do
def pending_correction?
return false if corrections.blank?
corrections.any? { _1[:resolved_at].nil? }
end
def resolved_corrections?
return false if corrections.blank?
corrections.all? { _1[:resolved_at].present? }
end
end
2021-04-21 12:02:57 +02:00
end
TABLE = 'table'
COLUMN = 'column'
# Returns [DossierProjection(dossier, columns)] ordered by dossiers_ids
# and the columns orderd by fields.
#
# It tries to be fast by using `pluck` (or at least `select`)
# to avoid deserializing entire records.
#
# It stores its intermediary queries results in an hash in the corresponding field.
# ex: field_email[:id_value_h] = { dossier_id_1: email_1, dossier_id_3: email_3 }
#
# Those hashes are needed because:
# - the order of the intermediary query results are unknown
# - some values can be missing (if a revision added or removed them)
def self.project(dossiers_ids, fields)
state_field = { TABLE => 'self', COLUMN => 'state' }
archived_field = { TABLE => 'self', COLUMN => 'archived' }
batch_operation_field = { TABLE => 'self', COLUMN => 'batch_operation_id' }
2021-11-24 10:35:19 +01:00
hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' }
hidden_by_administration_at_field = { TABLE => 'self', COLUMN => 'hidden_by_administration_at' }
2023-12-11 17:06:12 +01:00
for_tiers_field = { TABLE => 'self', COLUMN => 'for_tiers' }
individual_first_name = { TABLE => 'individual', COLUMN => 'prenom' }
individual_last_name = { TABLE => 'individual', COLUMN => 'nom' }
sva_svr_decision_on_field = { TABLE => 'self', COLUMN => 'sva_svr_decision_on' }
dossier_corrections = { TABLE => 'dossier_corrections', COLUMN => 'resolved_at' }
2023-12-11 17:06:12 +01:00
([state_field, archived_field, sva_svr_decision_on_field, hidden_by_user_at_field, hidden_by_administration_at_field, for_tiers_field, individual_first_name, individual_last_name, batch_operation_field, dossier_corrections] + fields) # the view needs state and archived dossier attributes
2021-04-22 22:27:38 +02:00
.each { |f| f[:id_value_h] = {} }
.group_by { |f| f[TABLE] } # one query per table
.each do |table, fields|
case table
when 'type_de_champ', 'type_de_champ_private'
Champ
.includes(:type_de_champ)
.where(
types_de_champ: { stable_id: fields.map { |f| f[COLUMN] } },
dossier_id: dossiers_ids
)
.select(:dossier_id, :value, :type_de_champ_id, :stable_id, :type, :external_id, :data, :value_json) # we cannot pluck :value, as we need the champ.to_s method
2021-04-22 22:27:38 +02:00
.group_by(&:stable_id) # the champs are redispatched to their respective fields
.map do |stable_id, champs|
field = fields.find { |f| f[COLUMN] == stable_id.to_s }
field[:id_value_h] = champs.to_h { |c| [c.dossier_id, c.to_s] }
end
2021-04-21 12:02:57 +02:00
when 'self'
Dossier
.where(id: dossiers_ids)
2021-04-22 22:27:38 +02:00
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
.each do |id, *columns|
fields.zip(columns).each do |field, value|
2023-12-11 17:06:12 +01:00
if [state_field, archived_field, hidden_by_user_at_field, hidden_by_administration_at_field, for_tiers_field, batch_operation_field, sva_svr_decision_on_field].include?(field)
field[:id_value_h][id] = value
else
field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime
end
end
end
2021-04-21 12:02:57 +02:00
when 'individual'
Individual
.where(dossier_id: dossiers_ids)
2021-04-22 22:27:38 +02:00
.pluck(:dossier_id, *fields.map { |f| f[COLUMN].to_sym })
.each { |id, *columns| fields.zip(columns).each { |field, value| field[:id_value_h][id] = value } }
2021-04-21 12:02:57 +02:00
when 'etablissement'
Etablissement
.where(dossier_id: dossiers_ids)
2021-04-22 22:27:38 +02:00
.pluck(:dossier_id, *fields.map { |f| f[COLUMN].to_sym })
.each { |id, *columns| fields.zip(columns).each { |field, value| field[:id_value_h][id] = value } }
when 'user'
fields[0][:id_value_h] = Dossier # there is only one field available for user table
.joins(:user)
.where(id: dossiers_ids)
.pluck('dossiers.id, users.email')
2021-04-21 12:02:57 +02:00
.to_h
when 'groupe_instructeur'
2021-04-22 22:27:38 +02:00
fields[0][:id_value_h] = Dossier
2021-04-21 12:02:57 +02:00
.joins(:groupe_instructeur)
.where(id: dossiers_ids)
.pluck('dossiers.id, groupe_instructeurs.label')
.to_h
when 'dossier_corrections'
columns = fields.map { _1[COLUMN].to_sym }
id_value_h = DossierCorrection.where(dossier_id: dossiers_ids)
.pluck(:dossier_id, *columns)
.group_by(&:first) # group corrections by dossier_id
.transform_values do |values| # build each correction has an hash column => value
values.map { Hash[columns.zip(_1[1..-1])] }
end
fields[0][:id_value_h] = id_value_h
2021-04-29 09:33:04 +02:00
when 'procedure'
Dossier
.joins(:procedure)
.where(id: dossiers_ids)
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
.each { |id, *columns| fields.zip(columns).each { |field, value| field[:id_value_h][id] = value } }
2021-04-21 12:02:57 +02:00
when 'followers_instructeurs'
# rubocop:disable Style/HashTransformValues
2021-04-22 22:27:38 +02:00
fields[0][:id_value_h] = Follow
2021-04-21 12:02:57 +02:00
.active
.joins(instructeur: :user)
.where(dossier_id: dossiers_ids)
.pluck('dossier_id, users.email')
.group_by { |dossier_id, _| dossier_id }
.to_h { |dossier_id, dossier_id_emails| [dossier_id, dossier_id_emails.sort.map { |_, email| email }&.join(', ')] }
# rubocop:enable Style/HashTransformValues
2023-04-20 11:44:35 +02:00
when 'avis'
# rubocop:disable Style/HashTransformValues
fields[0][:id_value_h] = Avis
.where(dossier_id: dossiers_ids)
.pluck('dossier_id', 'question_answer')
.group_by { |dossier_id, _| dossier_id }
2023-04-25 14:24:37 +02:00
.to_h { |dossier_id, question_answer| [dossier_id, question_answer.map { |_, answer| answer }&.compact&.tally&.map { |k, v| I18n.t("helpers.label.question_answer_with_count.#{k}", count: v) }&.join(' / ')] }
2023-04-20 11:44:35 +02:00
# rubocop:enable Style/HashTransformValues
2021-04-21 12:02:57 +02:00
end
end
dossiers_ids.map do |dossier_id|
DossierProjection.new(
dossier_id,
state_field[:id_value_h][dossier_id],
archived_field[:id_value_h][dossier_id],
2021-11-24 10:35:19 +01:00
hidden_by_user_at_field[:id_value_h][dossier_id],
hidden_by_administration_at_field[:id_value_h][dossier_id],
2023-12-11 17:06:12 +01:00
for_tiers_field[:id_value_h][dossier_id],
individual_first_name[:id_value_h][dossier_id],
individual_last_name[:id_value_h][dossier_id],
batch_operation_field[:id_value_h][dossier_id],
sva_svr_decision_on_field[:id_value_h][dossier_id],
dossier_corrections[:id_value_h][dossier_id],
fields.map { |f| f[:id_value_h][dossier_id] }
)
2021-04-21 12:02:57 +02:00
end
end
end