Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG. Co-authored-by: Cursor <cursoragent@cursor.com>
82 lines
2.5 KiB
Ruby
82 lines
2.5 KiB
Ruby
class Reports::Builder
|
|
def initialize(project: nil)
|
|
@project = project
|
|
@opp_scope = project ? Opportunity.for_project(project) : Opportunity.all
|
|
@org_scope = project ? Organization.for_project(project) : Organization.all
|
|
end
|
|
|
|
def funnel
|
|
metrics = Dashboard::Metrics.new(scope: @opp_scope, project: @project)
|
|
{
|
|
stages: Catalog::PIPELINE_ORDER.map { |s| { stage: s, label: Catalog.label_for(Catalog::PIPELINE_STAGES, s), count: metrics.stage_counts[s] } },
|
|
conversions: metrics.conversion_rates,
|
|
funnel: metrics.funnel_steps
|
|
}
|
|
end
|
|
|
|
def lead_sources
|
|
Catalog::LEAD_SOURCES.map do |key, label|
|
|
orgs = @org_scope.where(lead_source: key)
|
|
opps = @opp_scope.joins(:organization).where(organizations: { lead_source: key })
|
|
won = opps.won.count
|
|
leads = orgs.count
|
|
{
|
|
key: key,
|
|
label: label,
|
|
leads: leads,
|
|
opportunities: opps.count,
|
|
customers: won,
|
|
conversion_rate: leads.zero? ? 0 : ((won.to_f / leads) * 100).round
|
|
}
|
|
end
|
|
end
|
|
|
|
def won_lost_by_month(months: 6)
|
|
start_date = months.months.ago.beginning_of_month
|
|
won = @opp_scope.won.where("won_at >= ?", start_date).group("DATE_TRUNC('month', won_at)").count
|
|
lost = @opp_scope.lost.where("lost_at >= ?", start_date).group("DATE_TRUNC('month', lost_at)").count
|
|
keys = (won.keys + lost.keys).uniq.sort
|
|
keys.map do |month|
|
|
{
|
|
month: month.to_date,
|
|
won: won[month] || 0,
|
|
lost: lost[month] || 0
|
|
}
|
|
end
|
|
end
|
|
|
|
def lost_reasons
|
|
@opp_scope.lost.group(:lost_reason).count.map do |reason, count|
|
|
{
|
|
key: reason,
|
|
label: Catalog.label_for(Catalog::LOST_REASONS, reason),
|
|
count: count
|
|
}
|
|
end.sort_by { |r| -r[:count] }
|
|
end
|
|
|
|
def sales_owners
|
|
User.active.map do |user|
|
|
open_opps = user.assigned_opportunities.merge(@opp_scope).open_stage
|
|
won_opps = user.assigned_opportunities.merge(@opp_scope).won
|
|
{
|
|
user: user,
|
|
open_count: open_opps.count,
|
|
open_value: open_opps.sum(:estimated_value).to_f,
|
|
won_count: won_opps.count,
|
|
won_value: won_opps.sum(:estimated_value).to_f
|
|
}
|
|
end
|
|
end
|
|
|
|
def revenue_by_month(months: 6)
|
|
start_date = months.months.ago.beginning_of_month
|
|
@opp_scope.won
|
|
.where("won_at >= ?", start_date)
|
|
.group("DATE_TRUNC('month', won_at)")
|
|
.sum(:estimated_value)
|
|
.sort_by { |month, _| month }
|
|
.map { |month, value| { month: month.to_date, value: value.to_f } }
|
|
end
|
|
end
|