Aggiunge filtri avanzati per i destinatari delle campagne email.
La scelta della lista passa da un wizard a tre passi, con anteprima del conteggio e lista congelata solo dopo la conferma. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
module Mailings
|
||||
class AudienceQuery
|
||||
def initialize(project, filters = {}, mailing: nil)
|
||||
@project = project
|
||||
@filters = filters.is_a?(AudienceFilters) ? filters : AudienceFilters.new(filters)
|
||||
@mailing = mailing
|
||||
end
|
||||
|
||||
def relation
|
||||
scope = Organization.for_project(@project)
|
||||
scope = apply_preset(scope)
|
||||
scope = apply_organization_filters(scope)
|
||||
scope = apply_opportunity_filters(scope)
|
||||
scope = apply_history_filters(scope)
|
||||
scope = apply_exclusions(scope)
|
||||
scope.distinct
|
||||
end
|
||||
|
||||
def counts
|
||||
{
|
||||
total: relation.unscope(:order).distinct.count("organizations.id"),
|
||||
with_email: with_email_scope(relation).unscope(:order).distinct.count("organizations.id")
|
||||
}
|
||||
end
|
||||
|
||||
def preview(limit = 15)
|
||||
relation.includes(:primary_contact).reorder(Arel.sql("organizations.list_position ASC NULLS LAST"), "organizations.name ASC").limit(limit)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def apply_preset(scope)
|
||||
case @filters.preset
|
||||
when "to_send"
|
||||
scope.where(id: opportunity_scope.where(send_status: "to_send").select(:organization_id))
|
||||
when "test_a"
|
||||
scope.where(id: opportunity_scope.where(ab_variant: "A").select(:organization_id))
|
||||
when "test_b"
|
||||
scope.where(id: opportunity_scope.where(ab_variant: "B").select(:organization_id))
|
||||
else
|
||||
scope
|
||||
end
|
||||
end
|
||||
|
||||
def apply_organization_filters(scope)
|
||||
scope = scope.where(sport: @filters["sports"]) if @filters["sports"].present?
|
||||
scope = scope.where(team_gender: @filters["team_genders"]) if @filters["team_genders"].present?
|
||||
scope = scope.where(region: @filters["regions"]) if @filters["regions"].present?
|
||||
scope = scope.where(province: @filters["provinces"]) if @filters["provinces"].present?
|
||||
scope = scope.where(streaming_status: @filters["streaming_statuses"]) if @filters["streaming_statuses"].present?
|
||||
scope = scope.where(status: @filters["statuses"]) if @filters["statuses"].present?
|
||||
scope = scope.where("organizations.list_position >= ?", @filters["list_min"]) if @filters["list_min"].present?
|
||||
scope = scope.where("organizations.list_position <= ?", @filters["list_max"]) if @filters["list_max"].present?
|
||||
scope
|
||||
end
|
||||
|
||||
def apply_opportunity_filters(scope)
|
||||
extra = opportunity_scope
|
||||
filtered = false
|
||||
if @filters["send_statuses"].present?
|
||||
extra = extra.where(send_status: @filters["send_statuses"])
|
||||
filtered = true
|
||||
end
|
||||
if @filters["ab_variants"].present?
|
||||
extra = extra.where(ab_variant: @filters["ab_variants"])
|
||||
filtered = true
|
||||
end
|
||||
if @filters["pipeline_stages"].present?
|
||||
extra = extra.where(pipeline_stage: @filters["pipeline_stages"])
|
||||
filtered = true
|
||||
end
|
||||
case @filters["estimated_value"]
|
||||
when "present"
|
||||
extra = extra.where("opportunities.estimated_value IS NOT NULL AND opportunities.estimated_value > 0")
|
||||
filtered = true
|
||||
when "blank"
|
||||
extra = extra.where("opportunities.estimated_value IS NULL OR opportunities.estimated_value = 0")
|
||||
filtered = true
|
||||
end
|
||||
|
||||
filtered ? scope.where(id: extra.select(:organization_id)) : scope
|
||||
end
|
||||
|
||||
def apply_history_filters(scope)
|
||||
case @filters.history_kind
|
||||
when "never"
|
||||
scope.where.not(id: sent_org_ids)
|
||||
when "received"
|
||||
scope.where(id: sent_org_ids(mailing_id: @filters.history_mailing_id))
|
||||
when "not_received"
|
||||
scope.where.not(id: sent_org_ids(mailing_id: @filters.history_mailing_id))
|
||||
when "opened"
|
||||
scope.where(id: opened_org_ids(mailing_id: @filters.history_mailing_id))
|
||||
when "not_opened"
|
||||
sent = sent_org_ids(mailing_id: @filters.history_mailing_id)
|
||||
opened = opened_org_ids(mailing_id: @filters.history_mailing_id)
|
||||
scope.where(id: sent).where.not(id: opened)
|
||||
when "recent"
|
||||
days = @filters.history_days.presence || 30
|
||||
scope.where(id: sent_org_ids(since: days.days.ago))
|
||||
else
|
||||
scope
|
||||
end
|
||||
end
|
||||
|
||||
def apply_exclusions(scope)
|
||||
scope = scope.where.not(status: %w[active_customer inactive_customer]) if @filters["exclude_customers"]
|
||||
if @filters["exclude_received_mailing_ids"].present?
|
||||
scope = scope.where.not(id: sent_org_ids(mailing_id: project_mailing_ids(@filters["exclude_received_mailing_ids"])))
|
||||
end
|
||||
if @filters["exclude_opened_mailing_ids"].present?
|
||||
scope = scope.where.not(id: opened_org_ids(mailing_id: project_mailing_ids(@filters["exclude_opened_mailing_ids"])))
|
||||
end
|
||||
if @filters["exclude_mailed_within_days"].present?
|
||||
scope = scope.where.not(id: sent_org_ids(since: @filters["exclude_mailed_within_days"].days.ago))
|
||||
end
|
||||
scope
|
||||
end
|
||||
|
||||
def with_email_scope(scope)
|
||||
scope.left_joins(:contacts).where(
|
||||
"NULLIF(BTRIM(organizations.email), '') IS NOT NULL OR NULLIF(BTRIM(contacts.email), '') IS NOT NULL"
|
||||
)
|
||||
end
|
||||
|
||||
def opportunity_scope
|
||||
Opportunity.where(project_id: @project.id)
|
||||
end
|
||||
|
||||
def sent_org_ids(mailing_id: nil, since: nil)
|
||||
recips = history_recipients.where(status: "sent")
|
||||
recips = recips.where(mailing_id: mailing_id) if mailing_id.present?
|
||||
recips = recips.where("mailing_recipients.sent_at >= ?", since) if since.present?
|
||||
recips.select(:organization_id)
|
||||
end
|
||||
|
||||
def opened_org_ids(mailing_id: nil)
|
||||
recips = history_recipients.where.not(opened_at: nil)
|
||||
recips = recips.where(mailing_id: mailing_id) if mailing_id.present?
|
||||
recips.select(:organization_id)
|
||||
end
|
||||
|
||||
def history_recipients
|
||||
recips = MailingRecipient.joins(:mailing).where(mailings: { project_id: @project.id })
|
||||
recips = recips.where.not(mailing_id: @mailing.id) if @mailing&.persisted?
|
||||
recips
|
||||
end
|
||||
|
||||
def project_mailing_ids(ids)
|
||||
Mailing.for_project(@project).where(id: ids).select(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user