Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG. Co-authored-by: Cursor <cursoragent@cursor.com>
67 lines
2.1 KiB
Ruby
67 lines
2.1 KiB
Ruby
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
|