2019-08-19 16:12:30 +02:00
|
|
|
class GroupeInstructeur < ApplicationRecord
|
2023-05-16 11:16:35 +02:00
|
|
|
include Logic
|
2021-03-03 11:33:10 +01:00
|
|
|
DEFAUT_LABEL = 'défaut'
|
2020-07-20 17:22:44 +02:00
|
|
|
belongs_to :procedure, -> { with_discarded }, inverse_of: :groupe_instructeurs, optional: false
|
2020-06-11 10:08:04 +02:00
|
|
|
has_many :assign_tos, dependent: :destroy
|
|
|
|
has_many :instructeurs, through: :assign_tos
|
2019-08-22 17:58:31 +02:00
|
|
|
has_many :dossiers
|
2022-11-04 10:07:56 +01:00
|
|
|
has_many :deleted_dossiers
|
2022-12-22 22:23:47 +01:00
|
|
|
has_many :batch_operations, through: :dossiers, source: :batch_operations
|
2023-07-13 16:47:55 +02:00
|
|
|
has_many :assignments, class_name: 'DossierAssignment', dependent: :nullify, inverse_of: :groupe_instructeur
|
|
|
|
has_many :previous_assignments, class_name: 'DossierAssignment', dependent: :nullify, inverse_of: :previous_groupe_instructeur
|
2020-06-11 12:33:29 +02:00
|
|
|
has_and_belongs_to_many :exports, dependent: :destroy
|
2021-12-09 12:20:22 +01:00
|
|
|
has_and_belongs_to_many :bulk_messages, dependent: :destroy
|
2019-10-09 18:05:43 +02:00
|
|
|
|
2023-04-19 13:52:01 +02:00
|
|
|
has_one :defaut_procedure, -> { with_discarded }, class_name: 'Procedure', foreign_key: :defaut_groupe_instructeur_id, dependent: :nullify, inverse_of: :defaut_groupe_instructeur
|
2023-08-11 10:49:16 +02:00
|
|
|
has_one :contact_information
|
2023-04-19 13:52:01 +02:00
|
|
|
|
2023-09-19 15:41:51 +02:00
|
|
|
has_one_attached :signature
|
|
|
|
|
|
|
|
SIGNATURE_MAX_SIZE = 1.megabytes
|
|
|
|
validates :signature, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: SIGNATURE_MAX_SIZE }
|
|
|
|
|
2022-11-23 09:10:39 +01:00
|
|
|
validates :label, presence: true, allow_nil: false
|
|
|
|
validates :label, uniqueness: { scope: :procedure }
|
2023-08-04 14:50:43 +02:00
|
|
|
validates :closed, acceptance: { accept: [false] }, if: -> { (self == procedure.defaut_groupe_instructeur) }
|
2019-10-09 18:05:43 +02:00
|
|
|
|
|
|
|
before_validation -> { label&.strip! }
|
2020-01-07 17:39:50 +01:00
|
|
|
|
|
|
|
scope :without_group, -> (group) { where.not(id: group) }
|
2020-04-08 19:30:16 +02:00
|
|
|
scope :for_api_v2, -> { includes(procedure: [:administrateurs]) }
|
2022-11-23 09:10:39 +01:00
|
|
|
scope :active, -> { where(closed: false) }
|
|
|
|
scope :closed, -> { where(closed: true) }
|
2023-07-13 17:58:11 +02:00
|
|
|
scope :for_dossiers, -> (dossiers) { joins(:dossiers).where(dossiers: dossiers).distinct(:id) }
|
2021-12-21 19:06:38 +01:00
|
|
|
def add(instructeur)
|
2022-12-01 18:14:08 +01:00
|
|
|
return if instructeur.nil?
|
2021-12-21 19:06:38 +01:00
|
|
|
return if in?(instructeur.groupe_instructeurs)
|
|
|
|
|
|
|
|
default_notification_settings = instructeur.notification_settings(procedure_id)
|
|
|
|
instructeur.assign_to.create(groupe_instructeur: self, **default_notification_settings)
|
|
|
|
end
|
|
|
|
|
|
|
|
def remove(instructeur)
|
2022-12-01 18:14:08 +01:00
|
|
|
return if instructeur.nil?
|
2021-12-21 19:06:38 +01:00
|
|
|
return if !in?(instructeur.groupe_instructeurs)
|
|
|
|
|
|
|
|
instructeur.groupe_instructeurs.destroy(self)
|
|
|
|
instructeur.follows
|
|
|
|
.joins(:dossier)
|
|
|
|
.where(dossiers: { groupe_instructeur: self })
|
|
|
|
.update_all(unfollowed_at: Time.zone.now)
|
|
|
|
end
|
2022-10-20 18:24:27 +02:00
|
|
|
|
2023-02-21 16:37:26 +01:00
|
|
|
def add_instructeurs(ids: [], emails: [])
|
|
|
|
instructeurs_to_add, valid_emails, invalid_emails = Instructeur.find_all_by_identifier_with_emails(ids:, emails:)
|
|
|
|
not_found_emails = valid_emails - instructeurs_to_add.map(&:email)
|
|
|
|
|
|
|
|
# Send invitations to users without account
|
|
|
|
if not_found_emails.present?
|
|
|
|
instructeurs_to_add += not_found_emails.map do |email|
|
|
|
|
user = User.create_or_promote_to_instructeur(email, SecureRandom.hex, administrateurs: procedure.administrateurs)
|
|
|
|
user.invite!
|
|
|
|
user.instructeur
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# We dont't want to assign a user to a groupe_instructeur if they are already assigned to it
|
|
|
|
instructeurs_to_add -= instructeurs
|
2023-02-21 17:36:34 +01:00
|
|
|
instructeurs_to_add.each { add(_1) }
|
2023-02-21 16:37:26 +01:00
|
|
|
|
|
|
|
[instructeurs_to_add, invalid_emails]
|
|
|
|
end
|
|
|
|
|
2022-10-20 18:24:27 +02:00
|
|
|
def can_delete?
|
2022-11-23 09:10:39 +01:00
|
|
|
dossiers.empty? && (procedure.groupe_instructeurs.active.many? || (procedure.groupe_instructeurs.active.one? && closed))
|
2022-10-20 18:24:27 +02:00
|
|
|
end
|
2022-10-25 14:27:51 +02:00
|
|
|
|
2023-04-24 15:32:58 +02:00
|
|
|
def routing_to_configure?
|
2023-06-16 15:11:33 +02:00
|
|
|
invalid_rule? || non_unique_rule?
|
|
|
|
end
|
|
|
|
|
|
|
|
def invalid_rule?
|
2023-09-05 14:34:46 +02:00
|
|
|
!valid_rule?
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_rule?
|
|
|
|
return false if routing_rule.nil?
|
2023-10-13 15:00:07 +02:00
|
|
|
if [And, Or].include?(routing_rule.class)
|
|
|
|
routing_rule.operands.all? { |rule_line| valid_rule_line?(rule_line) }
|
|
|
|
else
|
|
|
|
valid_rule_line?(routing_rule)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_rule_line?(rule)
|
2023-11-22 12:04:25 +01:00
|
|
|
!rule.is_a?(EmptyOperator) && routing_rule_matches_tdc?(rule)
|
2023-05-16 11:16:35 +02:00
|
|
|
end
|
|
|
|
|
2023-06-16 15:11:33 +02:00
|
|
|
def non_unique_rule?
|
|
|
|
return false if invalid_rule?
|
|
|
|
routing_rule.in?(other_groupe_instructeurs.map(&:routing_rule))
|
2023-05-16 11:16:35 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def groups_with_same_rule
|
|
|
|
return if routing_rule.nil?
|
|
|
|
other_groupe_instructeurs
|
2023-10-13 15:00:07 +02:00
|
|
|
.filter { _1.routing_rule.present? }
|
|
|
|
.filter { _1.routing_rule == routing_rule }
|
2023-05-16 11:16:35 +02:00
|
|
|
.map(&:label)
|
|
|
|
.join(', ')
|
2023-04-24 15:32:58 +02:00
|
|
|
end
|
|
|
|
|
2023-05-16 11:21:26 +02:00
|
|
|
def other_groupe_instructeurs
|
|
|
|
procedure.groupe_instructeurs - [self]
|
|
|
|
end
|
|
|
|
|
2023-11-16 17:55:00 +01:00
|
|
|
def humanized_routing_rule
|
|
|
|
routing_rule&.to_s(procedure.active_revision.types_de_champ)
|
|
|
|
end
|
|
|
|
|
2022-10-25 14:27:51 +02:00
|
|
|
private
|
|
|
|
|
2023-10-13 15:00:07 +02:00
|
|
|
def routing_rule_matches_tdc?(rule)
|
2023-11-06 17:44:21 +01:00
|
|
|
tdcs = procedure.active_revision.types_de_champ_public
|
|
|
|
rule.errors(tdcs).blank?
|
2023-05-15 11:40:03 +02:00
|
|
|
end
|
|
|
|
|
2023-03-24 11:10:39 +01:00
|
|
|
serialize :routing_rule, LogicSerializer
|
2019-08-19 16:12:30 +02:00
|
|
|
end
|