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" elsif email_marked_invalid?(org, contact, email) attrs[:status] = "skipped" attrs[:skip_reason] = "email bounce / 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 def email_marked_invalid?(org, contact, email) email = email.to_s.downcase if contact&.email.to_s.downcase == email && contact.email_invalid? true elsif org.email.to_s.downcase == email && org.email_invalid? true elsif contact&.bounced_email.to_s.downcase == email || org.bounced_email.to_s.downcase == email true else false end end end