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 orgs = Organization.for_project(@mailing.project).includes(:contacts, :opportunities) org_ids = case @mailing.audience when "to_send" Opportunity.where(project_id: @mailing.project_id, send_status: "to_send").select(:organization_id) when "test_a" Opportunity.where(project_id: @mailing.project_id, ab_variant: "A").select(:organization_id) when "test_b" Opportunity.where(project_id: @mailing.project_id, ab_variant: "B").select(:organization_id) else orgs.select(:id) end orgs.where(id: org_ids) 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