demarches-normaliennes/app/models/dossier.rb

340 lines
11 KiB
Ruby
Raw Normal View History

2018-03-06 13:44:29 +01:00
class Dossier < ApplicationRecord
enum state: {
brouillon: 'brouillon',
en_construction: 'en_construction',
en_instruction: 'en_instruction',
accepte: 'accepte',
refuse: 'refuse',
sans_suite: 'sans_suite'
}
EN_CONSTRUCTION_OU_INSTRUCTION = %w(en_construction en_instruction)
TERMINE = %w(accepte refuse sans_suite)
INSTRUCTION_COMMENCEE = TERMINE + %w(en_instruction)
SOUMIS = EN_CONSTRUCTION_OU_INSTRUCTION + TERMINE
2015-09-24 11:45:00 +02:00
has_one :etablissement, dependent: :destroy
has_one :entreprise, dependent: :destroy
2016-08-30 11:18:43 +02:00
has_one :individual, dependent: :destroy
2017-06-02 14:30:26 +02:00
has_one :attestation
has_many :cerfa, dependent: :destroy
2015-09-24 11:45:00 +02:00
has_many :pieces_justificatives, dependent: :destroy
2018-02-09 17:38:30 +01:00
has_many :champs, -> { public_only }, dependent: :destroy
has_many :champs_private, -> { private_only }, class_name: 'Champ', dependent: :destroy
has_many :quartier_prioritaires, dependent: :destroy
2016-01-18 12:03:18 +01:00
has_many :cadastres, dependent: :destroy
has_many :commentaires, dependent: :destroy
has_many :invites, dependent: :destroy
has_many :invites_user, class_name: 'InviteUser', dependent: :destroy
2017-04-14 18:20:14 +02:00
has_many :invites_gestionnaires, class_name: 'InviteGestionnaire', dependent: :destroy
has_many :follows
2017-04-25 12:09:11 +02:00
has_many :avis, dependent: :destroy
belongs_to :procedure
2015-09-23 12:16:21 +02:00
belongs_to :user
2017-08-02 14:56:08 +02:00
accepts_nested_attributes_for :champs
2017-08-02 15:33:23 +02:00
accepts_nested_attributes_for :champs_private
2017-08-02 14:56:08 +02:00
2018-02-08 17:13:15 +01:00
validates :autorisation_donnees, acceptance: { message: 'doit être coché' }, allow_nil: false, on: :update
default_scope { where(hidden_at: nil) }
scope :state_brouillon, -> { where(state: 'brouillon') }
scope :state_not_brouillon, -> { where.not(state: 'brouillon') }
scope :state_en_construction, -> { where(state: 'en_construction') }
scope :state_en_instruction, -> { where(state: 'en_instruction') }
2017-07-11 16:09:03 +02:00
scope :state_en_construction_ou_instruction, -> { where(state: EN_CONSTRUCTION_OU_INSTRUCTION) }
scope :state_termine, -> { where(state: TERMINE) }
scope :archived, -> { where(archived: true) }
scope :not_archived, -> { where(archived: false) }
scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) }
scope :all_state, -> { not_archived.state_not_brouillon }
scope :en_construction, -> { not_archived.state_en_construction }
scope :en_instruction, -> { not_archived.state_en_instruction }
scope :termine, -> { not_archived.state_termine }
scope :downloadable_sorted, -> { state_not_brouillon.includes(:entreprise, :etablissement, :champs, :champs_private).order(en_construction_at: 'asc') }
scope :en_cours, -> { not_archived.state_en_construction_ou_instruction }
scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) }
2018-01-15 21:49:52 +01:00
scope :followed_by, -> (gestionnaire) { joins(:follows).where(follows: { gestionnaire: gestionnaire }) }
scope :with_ordered_champs, -> { includes(champs: :type_de_champ).order('types_de_champ.order_place') }
2016-08-30 11:18:43 +02:00
accepts_nested_attributes_for :individual
delegate :siren, to: :entreprise
delegate :siret, to: :etablissement, allow_nil: true
delegate :types_de_piece_justificative, to: :procedure
2015-11-05 11:21:44 +01:00
delegate :types_de_champ, to: :procedure
delegate :france_connect_information, to: :user
2017-03-01 09:51:55 +01:00
before_validation :update_state_dates, if: -> { state_changed? }
2018-01-30 17:14:56 +01:00
after_save :build_default_champs, if: Proc.new { saved_change_to_procedure_id? }
2016-08-30 11:18:43 +02:00
after_save :build_default_individual, if: Proc.new { procedure.for_individual? }
after_save :send_dossier_received
2018-03-01 17:04:05 +01:00
after_save :send_web_hook
after_create :send_draft_notification_email
validates :user, presence: true
2015-08-21 11:37:13 +02:00
def was_piece_justificative_uploaded_for_type_id?(type_id)
pieces_justificatives.where(type_de_piece_justificative_id: type_id).count > 0
end
2016-03-17 14:50:10 +01:00
def retrieve_last_piece_justificative_by_type(type)
pieces_justificatives.where(type_de_piece_justificative_id: type).last
end
2016-03-17 14:50:10 +01:00
def retrieve_all_piece_justificative_by_type(type)
pieces_justificatives.where(type_de_piece_justificative_id: type).order(created_at: :DESC)
end
def build_default_champs
2018-02-09 17:38:30 +01:00
procedure.all_types_de_champ.each do |type_de_champ|
type_de_champ.champ.create(dossier: self)
end
end
2016-08-30 11:18:43 +02:00
def build_default_individual
if Individual.where(dossier_id: self.id).count == 0
Individual.create(dossier: self)
end
2016-08-30 11:18:43 +02:00
end
def ordered_champs
# TODO: use the line below when the procedure preview does not leak champ with dossier_id == 0
# champs.joins(:type_de_champ).order('types_de_champ.order_place')
champs.joins(', types_de_champ').where("champs.type_de_champ_id = types_de_champ.id AND types_de_champ.procedure_id = #{procedure.id}").order('order_place')
end
def ordered_champs_private
# TODO: use the line below when the procedure preview does not leak champ with dossier_id == 0
# champs_private.includes(:type_de_champ).order('types_de_champ.order_place')
champs_private.joins(', types_de_champ').where("champs.type_de_champ_id = types_de_champ.id AND types_de_champ.procedure_id = #{procedure.id}").order('order_place')
end
2016-10-07 15:16:03 +02:00
def ordered_pieces_justificatives
champs.joins(', types_de_piece_justificative').where("pieces_justificatives.type_de_piece_justificative_id = types_de_piece_justificative.id AND types_de_piece_justificative.procedure_id = #{procedure.id}").order('order_place ASC')
end
def en_construction_ou_instruction?
EN_CONSTRUCTION_OU_INSTRUCTION.include?(state)
end
def termine?
TERMINE.include?(state)
end
2016-02-02 18:37:38 +01:00
def cerfa_available?
procedure.cerfa_flag? && cerfa.size != 0
2016-02-02 18:37:38 +01:00
end
2016-11-14 17:43:34 +01:00
def convert_specific_hash_values_to_string(hash_to_convert)
2018-01-16 14:24:11 +01:00
hash_to_convert.transform_values do |value|
serialize_value_for_export(value)
end
end
def full_data_strings_array
to_sorted_values.map do |value|
serialize_value_for_export(value)
2016-11-14 17:43:34 +01:00
end
end
def export_entreprise_data
2018-01-11 19:04:39 +01:00
if entreprise.present?
2018-01-16 14:24:51 +01:00
etablissement_attr = EtablissementCsvSerializer.new(self.etablissement).attributes.transform_keys { |k| "etablissement.#{k}".parameterize.underscore.to_sym }
entreprise_attr = EntrepriseSerializer.new(self.entreprise).attributes.transform_keys { |k| "entreprise.#{k}".parameterize.underscore.to_sym }
else
2018-01-16 14:24:51 +01:00
etablissement_attr = EtablissementSerializer.new(Etablissement.new).attributes.transform_keys { |k| "etablissement.#{k}".parameterize.underscore.to_sym }
entreprise_attr = EntrepriseSerializer.new(Entreprise.new).attributes.transform_keys { |k| "entreprise.#{k}".parameterize.underscore.to_sym }
2016-10-07 15:34:10 +02:00
end
2017-10-26 16:12:25 +02:00
convert_specific_hash_values_to_string(etablissement_attr.merge(entreprise_attr))
end
2016-10-07 15:34:10 +02:00
def to_sorted_values
serialized_dossier = DossierTableExportSerializer.new(self)
values = serialized_dossier.attributes.values
values += self.ordered_champs.map(&:for_export)
values += self.ordered_champs_private.map(&:for_export)
values += self.export_entreprise_data.values
values
end
def export_headers
serialized_dossier = DossierTableExportSerializer.new(self)
headers = serialized_dossier.attributes.keys
headers += self.procedure.types_de_champ.order(:order_place).map { |types_de_champ| types_de_champ.libelle.parameterize.underscore.to_sym }
headers += self.procedure.types_de_champ_private.order(:order_place).map { |types_de_champ| types_de_champ.libelle.parameterize.underscore.to_sym }
headers += self.export_entreprise_data.keys
2017-10-26 16:12:25 +02:00
headers
end
2017-04-14 18:10:39 +02:00
def followers_gestionnaires
follows.includes(:gestionnaire).map(&:gestionnaire)
2017-01-26 17:54:04 +01:00
end
def reset!
etablissement.destroy
2018-02-08 17:13:15 +01:00
update_columns(autorisation_donnees: false)
end
def total_follow
follows.size
end
2016-09-13 12:17:56 +02:00
def read_only?
en_instruction? || accepte? || refuse? || sans_suite?
2016-09-13 12:17:56 +02:00
end
def owner_or_invite?(user)
self.user == user || invite_for_user(user).present?
end
def invite_for_user(user)
invites_user.find_by(user_id: user.id)
end
2017-03-01 09:51:55 +01:00
def can_be_en_construction?
2017-12-04 16:17:15 +01:00
!(procedure.archivee? && brouillon?)
2017-03-06 18:17:28 +01:00
end
2017-04-18 17:31:01 +02:00
def text_summary
if brouillon?
parts = [
2017-04-26 15:08:15 +02:00
"Dossier en brouillon répondant à la procédure ",
2017-04-18 17:31:01 +02:00
procedure.libelle,
" gérée par l'organisme ",
2017-04-18 17:31:01 +02:00
procedure.organisation
]
else
parts = [
"Dossier déposé le ",
en_construction_at.localtime.strftime("%d/%m/%Y"),
2017-04-26 15:08:15 +02:00
" sur la procédure ",
2017-04-18 17:31:01 +02:00
procedure.libelle,
" gérée par l'organisme ",
2017-04-18 17:31:01 +02:00
procedure.organisation
]
end
parts.join
end
2017-09-08 11:52:20 +02:00
def avis_for(gestionnaire)
if gestionnaire.dossiers.include?(self)
avis.order(created_at: :asc)
else
avis
.where(confidentiel: false)
.or(avis.where(claimant: gestionnaire))
.or(avis.where(gestionnaire: gestionnaire))
.order(created_at: :asc)
end
end
def get_value(table, column)
case table
when 'self'
self.send(column)
when 'user'
self.user.send(column)
when 'france_connect_information'
self.user.france_connect_information&.send(column)
when 'entreprise'
self.entreprise&.send(column)
when 'etablissement'
self.etablissement&.send(column)
when 'type_de_champ'
self.champs.find { |c| c.type_de_champ_id == column.to_i }.value
when 'type_de_champ_private'
self.champs_private.find { |c| c.type_de_champ_id == column.to_i }.value
end
end
2017-09-27 15:16:07 +02:00
def self.sanitize_for_order(order)
sanitize_sql_for_order(order)
end
2017-11-17 23:40:51 +01:00
def owner_name
if entreprise.present?
entreprise.raison_sociale
elsif individual.present?
"#{individual.nom} #{individual.prenom}"
end
end
2017-11-22 15:40:53 +01:00
def statut
2017-12-04 18:00:12 +01:00
if accepte?
2017-11-22 15:40:53 +01:00
'accepté'
elsif sans_suite?
2017-11-22 15:40:53 +01:00
'classé sans suite'
2017-12-04 18:15:40 +01:00
elsif refuse?
2017-11-22 15:40:53 +01:00
'refusé'
end
end
def user_geometry
if json_latlngs.present?
UserGeometry.new(json_latlngs)
end
end
def unspecified_attestation_champs
attestation_template = procedure.attestation_template
if attestation_template&.activated?
attestation_template.unspecified_champs_for_dossier(self)
else
[]
end
end
def build_attestation
if procedure.attestation_template&.activated?
procedure.attestation_template.attestation_for(self)
end
end
2017-12-05 17:43:32 +01:00
private
2017-03-01 09:51:55 +01:00
def update_state_dates
if en_construction? && !self.en_construction_at
self.en_construction_at = DateTime.now
elsif en_instruction? && !self.en_instruction_at
self.en_instruction_at = DateTime.now
2017-03-01 09:51:55 +01:00
elsif TERMINE.include?(state)
self.processed_at = DateTime.now
end
end
def serialize_value_for_export(value)
value.nil? || value.kind_of?(Time) ? value : value.to_s
end
def send_dossier_received
2018-01-30 17:14:56 +01:00
if saved_change_to_state? && en_instruction?
NotificationMailer.send_dossier_received(id).deliver_later
end
end
def send_draft_notification_email
if brouillon?
NotificationMailer.send_draft_notification(self).deliver_now!
end
end
2018-03-01 17:04:05 +01:00
def send_web_hook
if saved_change_to_state? && !brouillon? && procedure.web_hook_url
WebHookJob.perform_later(
procedure,
self
)
end
end
2015-08-10 11:05:06 +02:00
end