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>
58 lines
1.6 KiB
Ruby
58 lines
1.6 KiB
Ruby
class Mailings::RecipientBuilder
|
|
def initialize(mailing)
|
|
@mailing = mailing
|
|
end
|
|
|
|
def call
|
|
split_index = 0
|
|
ordered_scope.each do |org|
|
|
contact = org.primary_contact || org.contacts.min_by(&:id)
|
|
email = contact&.email.presence || org.email.presence
|
|
attrs = {
|
|
organization: org,
|
|
contact: contact,
|
|
email: email&.downcase
|
|
}
|
|
if email.blank?
|
|
attrs[:status] = "skipped"
|
|
attrs[:skip_reason] = "manca email"
|
|
elsif !email.match?(URI::MailTo::EMAIL_REGEXP)
|
|
attrs[:status] = "skipped"
|
|
attrs[:skip_reason] = "email non valida"
|
|
else
|
|
attrs[:status] = "pending"
|
|
end
|
|
assign_variant!(attrs, org, split_index)
|
|
split_index += 1 if attrs[:status] == "pending"
|
|
@mailing.mailing_recipients.create!(attrs)
|
|
end
|
|
@mailing.mailing_recipients.ordered
|
|
end
|
|
|
|
private
|
|
|
|
def ordered_scope
|
|
scope.reorder(Arel.sql("organizations.list_position ASC NULLS LAST"), "organizations.name ASC")
|
|
end
|
|
|
|
def scope
|
|
Mailings::AudienceQuery.new(@mailing.project, @mailing.parsed_audience_filters, mailing: @mailing)
|
|
.relation
|
|
.includes(:contacts, :opportunities)
|
|
end
|
|
|
|
def assign_variant!(attrs, org, split_index)
|
|
return unless @mailing.ab_test?
|
|
|
|
opportunity = org.campaign_opportunity(@mailing.project)
|
|
recorded = opportunity&.ab_variant.to_s.upcase
|
|
variant =
|
|
if @mailing.ab_from_record? && recorded.in?(%w[A B])
|
|
recorded
|
|
else
|
|
split_index.even? ? "A" : "B"
|
|
end
|
|
attrs[:ab_variant] = variant
|
|
end
|
|
end
|