class SalesGoal < ApplicationRecord include Auditable belongs_to :project, optional: true validates :name, :metric, :target_value, :start_date, :end_date, presence: true validates :metric, inclusion: { in: Catalog::GOAL_METRICS.keys } validates :target_value, numericality: { greater_than: 0 } validate :end_date_after_start_date scope :active, -> { where(active: true) } scope :for_project, ->(project) { return none if project.nil? where(project_id: project.id) } scope :current, ->(project = nil) { today = Time.zone.today scope = active.where("start_date <= ? AND end_date >= ?", today, today) scope = scope.where(project_id: project.id) if project scope } def metric_label Catalog.label_for(Catalog::GOAL_METRICS, metric) end def current_value opps = project ? Opportunity.for_project(project) : Opportunity.all activities = if project Activity.joins(:organization) .joins("INNER JOIN organization_projects ON organization_projects.organization_id = activities.organization_id") .where(organization_projects: { project_id: project.id }) else Activity.all end case metric when "customers_acquired" opps.won.where(won_at: start_date.beginning_of_day..end_date.end_of_day).count when "won_value" opps.won.where(won_at: start_date.beginning_of_day..end_date.end_of_day).sum(:estimated_value).to_f when "trials" activities.where(activity_type: "trial_started", happened_at: start_date.beginning_of_day..end_date.end_of_day).count when "first_uses" activities.where(activity_type: "first_use", happened_at: start_date.beginning_of_day..end_date.end_of_day).count else 0 end end def progress_percentage return 0 if target_value.to_f.zero? [[(current_value.to_f / target_value.to_f * 100).round, 0].max, 100].min end private def end_date_after_start_date return if start_date.blank? || end_date.blank? return if end_date >= start_date errors.add(:end_date, "deve essere successiva alla data di inizio") end end