class Organization < ApplicationRecord include Auditable belongs_to :assigned_user, class_name: "User", optional: true has_many :organization_projects, dependent: :destroy has_many :projects, through: :organization_projects has_many :contacts, dependent: :destroy has_many :opportunities, dependent: :destroy has_many :activities, dependent: :destroy has_many :tasks, dependent: :destroy has_many :mailing_recipients, dependent: :destroy has_one :primary_contact, -> { where(primary_contact: true) }, class_name: "Contact", inverse_of: :organization validates :name, presence: true validates :status, inclusion: { in: Catalog::ORGANIZATION_STATUSES.keys } validates :organization_type, inclusion: { in: Catalog::ORGANIZATION_TYPES.keys } validates :lead_source, inclusion: { in: Catalog::LEAD_SOURCES.keys }, allow_blank: true validates :team_gender, inclusion: { in: Catalog::TEAM_GENDERS.keys }, allow_blank: true validates :streaming_status, inclusion: { in: Catalog::STREAMING_STATUSES.keys }, allow_blank: true validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }, allow_blank: true validate :must_have_at_least_one_project before_validation :assign_current_project_if_needed, on: :create scope :prospects, -> { where(status: "prospect") } scope :customers, -> { where(status: %w[active_customer inactive_customer]) } scope :active_customers, -> { where(status: "active_customer") } scope :for_project, ->(project) { return none if project.nil? joins(:organization_projects).where(organization_projects: { project_id: project.id }).distinct } scope :search, ->(query) { return all if query.blank? q = "%#{sanitize_sql_like(query.strip)}%" left_joins(:contacts).where( "organizations.name ILIKE :q OR organizations.city ILIKE :q OR organizations.email ILIKE :q OR organizations.phone ILIKE :q OR organizations.website ILIKE :q OR contacts.first_name ILIKE :q OR contacts.last_name ILIKE :q OR contacts.email ILIKE :q OR contacts.phone ILIKE :q OR contacts.mobile ILIKE :q", q: q ).distinct } def status_label Catalog.label_for(Catalog::ORGANIZATION_STATUSES, status) end def organization_type_label Catalog.label_for(Catalog::ORGANIZATION_TYPES, organization_type) end def lead_source_label Catalog.label_for(Catalog::LEAD_SOURCES, lead_source) end def team_gender_label Catalog.label_for(Catalog::TEAM_GENDERS, team_gender) end def streaming_status_label Catalog.label_for(Catalog::STREAMING_STATUSES, streaming_status) end def campaign_opportunity(project = nil) list = opportunities.to_a list = list.select { |opp| opp.project_id == project.id } if project list.max_by(&:updated_at) end def primary_pipeline_stage(project = nil) scope = opportunities scope = scope.where(project_id: project.id) if project scope.open_stage.order(updated_at: :desc).first&.pipeline_stage || scope.order(updated_at: :desc).first&.pipeline_stage end def next_pending_task tasks.pending.order(:due_at).first end def last_activity_at activities.maximum(:happened_at) end def days_since_last_activity return nil unless last_activity_at ((Time.current - last_activity_at) / 1.day).floor end def mark_as_active_customer! update!(status: "active_customer") if status != "active_customer" end def ensure_in_project!(project) return if project.nil? return if projects.exists?(project.id) projects << project end private def assign_current_project_if_needed return if organization_projects.any? || project_ids.reject(&:blank?).any? return unless Current.project organization_projects.build(project: Current.project) end def must_have_at_least_one_project return if organization_projects.any? || project_ids.reject(&:blank?).any? errors.add(:projects, "seleziona almeno un progetto") end end