Commit iniziale di eminuxCRM: CRM Rails con pipeline, campagne email e Docker.
Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
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
|
||||
Reference in New Issue
Block a user