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
2023-03-27 16:23:11 +02:00
def pending_correction?
2023-04-03 17:05:54 +02:00
return false if corrections . blank?
2023-03-27 16:23:11 +02:00
2023-04-03 17:05:54 +02:00
corrections . any? { _1 [ :resolved_at ] . nil? }
2023-03-27 16:23:11 +02:00
end
2024-01-24 17:01:59 +01:00
def resolved_corrections?
return false if corrections . blank?
corrections . all? { _1 [ :resolved_at ] . present? }
end
2023-03-27 16:23:11 +02:00
end
2021-04-21 12:02:57 +02:00
end
2024-01-30 10:56:57 +01:00
def self . for_tiers_translation ( array )
for_tiers , email , first_name , last_name = array
if for_tiers == true
" #{ email } #{ I18n . t ( 'views.instructeurs.dossiers.acts_on_behalf' ) } #{ first_name } #{ last_name } "
else
email
end
end
2021-04-21 12:02:57 +02:00
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 )
2021-04-26 10:35:22 +02:00
state_field = { TABLE = > 'self' , COLUMN = > 'state' }
archived_field = { TABLE = > 'self' , COLUMN = > 'archived' }
2022-11-21 18:08:34 +01:00
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' }
2022-02-02 19:34:00 +01:00
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' }
2023-06-07 17:25:41 +02:00
sva_svr_decision_on_field = { TABLE = > 'self' , COLUMN = > 'sva_svr_decision_on' }
2023-04-03 17:05:54 +02:00
dossier_corrections = { TABLE = > 'dossier_corrections' , COLUMN = > 'resolved_at' }
2024-04-24 10:50:17 +02:00
champ_value = champ_value_formatter ( dossiers_ids , fields )
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
. where (
2024-04-23 11:32:25 +02:00
stable_id : fields . map { | f | f [ COLUMN ] } ,
2021-04-22 22:27:38 +02:00
dossier_id : dossiers_ids
)
2024-04-23 11:32:25 +02:00
. select ( :dossier_id , :value , :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 }
2024-04-24 10:50:17 +02:00
field [ :id_value_h ] = champs . to_h { | c | [ c . dossier_id , champ_value . ( c ) ] }
2021-04-22 22:27:38 +02:00
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 } )
2021-04-26 10:35:22 +02:00
. 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 )
2021-04-26 10:35:22 +02:00
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'
2024-01-30 10:56:57 +01:00
2021-04-22 22:27:38 +02:00
fields [ 0 ] [ :id_value_h ] = Dossier # there is only one field available for user table
. joins ( :user )
2024-01-30 10:56:57 +01:00
. includes ( :individual )
2021-04-22 22:27:38 +02:00
. where ( id : dossiers_ids )
2024-01-30 10:56:57 +01:00
. pluck ( 'dossiers.id, dossiers.for_tiers, users.email, individuals.prenom, individuals.nom' )
. to_h { | dossier_id , * array | [ dossier_id , for_tiers_translation ( array ) ] }
2021-04-21 12:02:57 +02:00
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
2023-04-03 17:05:54 +02:00
when 'dossier_corrections'
2023-03-27 16:23:11 +02:00
columns = fields . map { _1 [ COLUMN ] . to_sym }
2023-04-03 17:05:54 +02:00
id_value_h = DossierCorrection . where ( dossier_id : dossiers_ids )
2023-03-27 16:23:11 +02:00
. pluck ( :dossier_id , * columns )
2023-04-03 17:05:54 +02:00
. group_by ( & :first ) # group corrections by dossier_id
. transform_values do | values | # build each correction has an hash column => value
2023-03-27 16:23:11 +02:00
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'
2021-06-10 15:24:15 +02:00
# 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 }
2021-05-04 15:41:38 +02:00
. to_h { | dossier_id , dossier_id_emails | [ dossier_id , dossier_id_emails . sort . map { | _ , email | email } & . join ( ', ' ) ] }
2021-06-10 15:24:15 +02:00
# 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
2021-04-26 10:35:22 +02:00
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 ] ,
2022-02-02 19:34:00 +01:00
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 ] ,
2022-11-21 18:08:34 +01:00
batch_operation_field [ :id_value_h ] [ dossier_id ] ,
2023-06-07 17:25:41 +02:00
sva_svr_decision_on_field [ :id_value_h ] [ dossier_id ] ,
2023-04-03 17:05:54 +02:00
dossier_corrections [ :id_value_h ] [ dossier_id ] ,
2021-04-26 10:35:22 +02:00
fields . map { | f | f [ :id_value_h ] [ dossier_id ] }
)
2021-04-21 12:02:57 +02:00
end
end
2024-04-24 10:50:17 +02:00
class << self
private
def champ_value_formatter ( dossiers_ids , fields )
stable_ids = fields . filter { _1 [ TABLE ] . in? ( [ 'type_de_champ' , 'type_de_champ_private' ] ) } . map { _1 [ COLUMN ] }
revision_ids_by_dossier_ids = Dossier . where ( id : dossiers_ids ) . pluck ( :id , :revision_id ) . to_h
stable_ids_and_types_champ_by_revision_ids = ProcedureRevisionTypeDeChamp . includes ( :type_de_champ )
. where ( revision_id : revision_ids_by_dossier_ids . values . uniq , type_de_champ : { stable_id : stable_ids } )
. pluck ( :revision_id , 'type_de_champ.stable_id' , 'type_de_champ.type_champ' )
. group_by ( & :first )
. transform_values { _1 . map { | _ , stable_id , type_champ | [ stable_id , type_champ ] } . to_h }
stable_ids_and_types_champ_by_dossier_ids = revision_ids_by_dossier_ids . transform_values { stable_ids_and_types_champ_by_revision_ids [ _1 ] } . compact
- > ( champ ) {
type_champ = stable_ids_and_types_champ_by_dossier_ids . fetch ( champ . dossier_id , { } ) [ champ . stable_id ]
if type_champ . present? && TypeDeChamp . type_champ_to_champ_class_name ( type_champ ) == champ . type
TypeDeChamp . champ_value ( type_champ , champ )
else
''
end
}
end
end
2021-04-21 12:02:57 +02:00
end