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:
@@ -16,11 +16,11 @@ class MailingsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_match(/Invii email/, response.body)
|
||||
end
|
||||
|
||||
test "creates a draft and builds recipients" do
|
||||
test "creates a draft and opens audience filters" do
|
||||
login_as users(:admin)
|
||||
follow_redirect! if response.redirect?
|
||||
|
||||
assert_difference -> { Mailing.count } => 1, -> { MailingRecipient.count } => 1 do
|
||||
assert_difference -> { Mailing.count } => 1, -> { MailingRecipient.count } => 0 do
|
||||
post mailings_path(project_code: @project.code), params: {
|
||||
mailing: {
|
||||
name: "Lancio",
|
||||
@@ -33,10 +33,59 @@ class MailingsControllerTest < ActionDispatch::IntegrationTest
|
||||
}
|
||||
end
|
||||
mailing = Mailing.last
|
||||
assert_redirected_to audience_mailing_path(mailing, project_code: @project.code)
|
||||
assert mailing.mailing_recipients.none?
|
||||
end
|
||||
|
||||
test "audience apply builds frozen recipient list" do
|
||||
login_as users(:admin)
|
||||
follow_redirect! if response.redirect?
|
||||
mailing = create_mailing(identity: @identity, audience: "to_send")
|
||||
|
||||
patch audience_mailing_path(mailing, project_code: @project.code), params: {
|
||||
intent: "apply",
|
||||
filters: { preset: "to_send" }
|
||||
}
|
||||
|
||||
assert_redirected_to mailing_path(mailing, project_code: @project.code)
|
||||
assert mailing.reload.mailing_recipients.any?
|
||||
assert_equal "pending", mailing.mailing_recipients.first.status
|
||||
end
|
||||
|
||||
test "audience page shows live filter counts" do
|
||||
login_as users(:admin)
|
||||
follow_redirect! if response.redirect?
|
||||
mailing = create_mailing(identity: @identity, audience: "to_send")
|
||||
|
||||
get audience_mailing_path(mailing, project_code: @project.code)
|
||||
assert_response :success
|
||||
assert_match(/Destinatari/, response.body)
|
||||
assert_match(/Corrispondenze/, response.body)
|
||||
assert_match(/Genera lista e rivedi/, response.body)
|
||||
assert_match(/Chi deve ricevere questa email/, response.body)
|
||||
assert_select "details[data-section=organization]"
|
||||
assert_select "details[data-section=campaign]"
|
||||
assert_select "details[data-section=history]"
|
||||
assert_select "details[data-section=exclusions]"
|
||||
end
|
||||
|
||||
test "audience preview saves filters without building recipients" do
|
||||
login_as users(:admin)
|
||||
follow_redirect! if response.redirect?
|
||||
mailing = create_mailing(identity: @identity, audience: "to_send")
|
||||
|
||||
patch audience_mailing_path(mailing, project_code: @project.code), params: {
|
||||
intent: "preview",
|
||||
filters: { preset: "all", sports: [ "Calcio" ] }
|
||||
}
|
||||
|
||||
assert_response :success
|
||||
assert_match(/Destinatari/, response.body)
|
||||
assert mailing.reload.mailing_recipients.none?
|
||||
assert_equal "all", mailing.audience
|
||||
assert_equal [ "Calcio" ], mailing.parsed_audience_filters["sports"]
|
||||
end
|
||||
|
||||
test "check recipients then queue send" do
|
||||
login_as users(:admin)
|
||||
follow_redirect! if response.redirect?
|
||||
@@ -125,7 +174,11 @@ class MailingsControllerTest < ActionDispatch::IntegrationTest
|
||||
}
|
||||
mailing = Mailing.last
|
||||
assert mailing.ab_test?
|
||||
assert_equal "A", mailing.mailing_recipients.first.ab_variant
|
||||
patch audience_mailing_path(mailing, project_code: @project.code), params: {
|
||||
intent: "apply",
|
||||
filters: { preset: "to_send" }
|
||||
}
|
||||
assert_equal "A", mailing.reload.mailing_recipients.first.ab_variant
|
||||
|
||||
assert_emails 1 do
|
||||
post test_send_mailing_path(mailing, project_code: @project.code), params: {
|
||||
@@ -184,7 +237,7 @@ class MailingsControllerTest < ActionDispatch::IntegrationTest
|
||||
}
|
||||
}
|
||||
mailing = Mailing.last
|
||||
assert_redirected_to mailing_path(mailing, project_code: @project.code)
|
||||
assert_redirected_to audience_mailing_path(mailing, project_code: @project.code)
|
||||
assert_equal "B {{societa}}", mailing.subject_b
|
||||
assert_includes mailing.body_html_b, "Versione B dal template"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
require "test_helper"
|
||||
|
||||
class MailingsAudienceQueryTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
opportunities(:deal).update!(send_status: "to_send", ab_variant: "A")
|
||||
@project = projects(:matchlivetv)
|
||||
@acme = organizations(:acme)
|
||||
@volley = create_campaign_org(
|
||||
name: "Volley Rosa",
|
||||
email: "volley@example.com",
|
||||
ab_variant: "B",
|
||||
send_status: "to_send",
|
||||
list_position: 20,
|
||||
sport: "Pallavolo",
|
||||
region: "Lazio",
|
||||
team_gender: "female"
|
||||
)
|
||||
@acme.update!(sport: "Calcio", region: "Lombardia", list_position: 1, team_gender: "male")
|
||||
end
|
||||
|
||||
test "preset to_send keeps campaign pending orgs" do
|
||||
ids = query({ "preset" => "to_send" }).relation.pluck(:id)
|
||||
assert_includes ids, @acme.id
|
||||
assert_includes ids, @volley.id
|
||||
end
|
||||
|
||||
test "filters by sport" do
|
||||
ids = query({ "preset" => "all", "sports" => ["Calcio"] }).relation.pluck(:id)
|
||||
assert_includes ids, @acme.id
|
||||
assert_not_includes ids, @volley.id
|
||||
end
|
||||
|
||||
test "filters by list position range" do
|
||||
ids = query({ "preset" => "all", "list_min" => 1, "list_max" => 5 }).relation.pluck(:id)
|
||||
assert_includes ids, @acme.id
|
||||
assert_not_includes ids, @volley.id
|
||||
end
|
||||
|
||||
test "history never excludes orgs already mailed" do
|
||||
previous = create_mailing(audience: "all")
|
||||
previous.rebuild_recipients!
|
||||
previous.mailing_recipients.find_by!(organization: @acme).update!(status: "sent", sent_at: 1.day.ago)
|
||||
|
||||
mailing = create_mailing(audience: "all")
|
||||
ids = query({ "preset" => "all", "history_kind" => "never" }, mailing: mailing).relation.pluck(:id)
|
||||
assert_not_includes ids, @acme.id
|
||||
assert_includes ids, @volley.id
|
||||
end
|
||||
|
||||
test "exclude customers drops active customers" do
|
||||
@volley.update!(status: "active_customer")
|
||||
ids = query({ "preset" => "all", "exclude_customers" => true }).relation.pluck(:id)
|
||||
assert_includes ids, @acme.id
|
||||
assert_not_includes ids, @volley.id
|
||||
end
|
||||
|
||||
test "recipient builder uses audience filters" do
|
||||
mailing = create_mailing(audience: "all", audience_filters: { "preset" => "all", "sports" => ["Pallavolo"] })
|
||||
mailing.rebuild_recipients!
|
||||
assert_equal [@volley.id], mailing.mailing_recipients.map(&:organization_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def query(filters = {}, mailing: nil)
|
||||
Mailings::AudienceQuery.new(@project, Mailings::AudienceFilters.new(filters), mailing: mailing)
|
||||
end
|
||||
end
|
||||
+8
-6
@@ -50,14 +50,16 @@ module MailMarketingTestHelper
|
||||
)
|
||||
end
|
||||
|
||||
def create_campaign_org(name:, email:, ab_variant: nil, send_status: "to_send", list_position: nil)
|
||||
def create_campaign_org(name:, email:, ab_variant: nil, send_status: "to_send", list_position: nil, **org_attrs)
|
||||
project = projects(:matchlivetv)
|
||||
org = Organization.new(
|
||||
name: name,
|
||||
status: "prospect",
|
||||
organization_type: "societa_sportiva",
|
||||
email: email,
|
||||
list_position: list_position
|
||||
{
|
||||
name: name,
|
||||
status: "prospect",
|
||||
organization_type: "societa_sportiva",
|
||||
email: email,
|
||||
list_position: list_position
|
||||
}.merge(org_attrs)
|
||||
)
|
||||
org.organization_projects.build(project: project)
|
||||
org.save!
|
||||
|
||||
Reference in New Issue
Block a user