84 lines
2.6 KiB
Ruby
84 lines
2.6 KiB
Ruby
class Api::V1::Accounts::LeadClickStatsController < Api::V1::Accounts::BaseController
|
|
def show
|
|
clicks = account_clicks
|
|
render json: stats_payload(clicks)
|
|
end
|
|
|
|
private
|
|
|
|
def account_clicks
|
|
scope = LeadClick.joins(:inbox).where(inboxes: { account_id: current_account.id })
|
|
scope = scope.where(inbox_id: params[:inbox_id]) if params[:inbox_id].present?
|
|
apply_period_filter(scope)
|
|
end
|
|
|
|
def apply_period_filter(scope)
|
|
return scope unless params[:period_start].present? && params[:period_end].present?
|
|
|
|
start_at = Time.zone.parse(params[:period_start].to_s)&.beginning_of_day
|
|
end_at = Time.zone.parse(params[:period_end].to_s)&.end_of_day
|
|
return scope unless start_at && end_at
|
|
|
|
scope.where(created_at: start_at..end_at)
|
|
end
|
|
|
|
def stats_payload(clicks)
|
|
total_clicks = clicks.count
|
|
total_conversions = clicks.where.not(conversation_id: nil).count
|
|
total_non_converted = total_clicks - total_conversions
|
|
|
|
{
|
|
total_clicks: total_clicks,
|
|
total_conversions: total_conversions,
|
|
total_non_converted: total_non_converted,
|
|
drop_off_rate: percentage(total_non_converted, total_clicks),
|
|
conversion_rate: percentage(total_conversions, total_clicks),
|
|
unique_click_ids: clicks.where.not(click_id: [nil, '']).distinct.count(:click_id),
|
|
unique_converted_contacts: clicks.where.not(contact_id: nil).distinct.count(:contact_id),
|
|
daily: daily_breakdown(clicks),
|
|
by_source: group_by(clicks, :source),
|
|
by_campaign: group_by(clicks, :campanha),
|
|
by_hostname: group_by(clicks, :hostname)
|
|
}
|
|
end
|
|
|
|
def percentage(part, total)
|
|
return 0 unless total.positive?
|
|
|
|
(part.to_f / total * 100).round(1)
|
|
end
|
|
|
|
def group_by(clicks, column)
|
|
rows = clicks
|
|
.group(column)
|
|
.select("#{column}, COUNT(*) AS clicks, COUNT(conversation_id) AS conversions")
|
|
|
|
grouped_rows = rows.map do |row|
|
|
{
|
|
label: row.public_send(column).presence || '(sem nome)',
|
|
clicks: row.clicks,
|
|
conversions: row.conversions,
|
|
rate: row.clicks.positive? ? (row.conversions.to_f / row.clicks * 100).round(1) : 0
|
|
}
|
|
end
|
|
|
|
grouped_rows.sort_by { |row| -row[:clicks] }
|
|
end
|
|
|
|
def daily_breakdown(clicks)
|
|
rows = clicks
|
|
.group('DATE(lead_clicks.created_at)')
|
|
.select('DATE(lead_clicks.created_at) AS day, COUNT(*) AS clicks, COUNT(lead_clicks.conversation_id) AS conversions')
|
|
.order('day ASC')
|
|
|
|
rows.map do |row|
|
|
{
|
|
day: row.day.to_s,
|
|
clicks: row.clicks.to_i,
|
|
conversions: row.conversions.to_i,
|
|
non_converted: row.clicks.to_i - row.conversions.to_i
|
|
}
|
|
end
|
|
end
|
|
end
|