iachat/app/controllers/api/v1/accounts/lead_click_stats_controller.rb

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