Improve campaign personalization and contact duplicate handling.
Add merge tags for email/SMS, paginated removable recipients, PCM event panels for postcard campaigns, and a portal modal when phone/address matches an existing contact.
This commit is contained in:
@@ -140,6 +140,10 @@ class PortalConsentToggleTests(TestCase):
|
||||
response = self.client.post(
|
||||
url,
|
||||
{
|
||||
"first_name": "Sam",
|
||||
"last_name": "",
|
||||
"email": "sam@example.com",
|
||||
"phone": "",
|
||||
"notes": "updated",
|
||||
"consent_sms": "1",
|
||||
"consent_postcard": "1",
|
||||
@@ -155,6 +159,32 @@ class PortalConsentToggleTests(TestCase):
|
||||
)
|
||||
self.assertEqual(email_consent.reason, "portal_manual")
|
||||
|
||||
def test_portal_can_update_profile(self):
|
||||
url = reverse("contacts:detail", kwargs={"pk": self.contact.pk})
|
||||
response = self.client.post(
|
||||
url,
|
||||
{
|
||||
"first_name": "Samantha",
|
||||
"last_name": "Lee",
|
||||
"email": "sam.lee@example.com",
|
||||
"phone": "6305550100",
|
||||
"address_line1": "10 Main St",
|
||||
"address_city": "Naperville",
|
||||
"address_state": "IL",
|
||||
"address_zip": "60540",
|
||||
"notes": "VIP",
|
||||
"consent_email": "1",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.contact.refresh_from_db()
|
||||
self.assertEqual(self.contact.first_name, "Samantha")
|
||||
self.assertEqual(self.contact.last_name, "Lee")
|
||||
self.assertEqual(self.contact.email, "sam.lee@example.com")
|
||||
self.assertEqual(self.contact.phone, "6305550100")
|
||||
self.assertEqual(self.contact.postal_address.get("line1"), "10 Main St")
|
||||
self.assertEqual(self.contact.notes, "VIP")
|
||||
|
||||
|
||||
class CampaignDraftSaveTests(TestCase):
|
||||
def setUp(self):
|
||||
@@ -899,3 +929,114 @@ class StoredFileUploadTests(TestCase):
|
||||
self.assertEqual(fetch.status_code, 200)
|
||||
self.assertEqual(fetch["Content-Type"], "image/png")
|
||||
self.assertEqual(b"".join(fetch.streaming_content), png)
|
||||
|
||||
|
||||
|
||||
class MergeTagTests(TestCase):
|
||||
def test_render_merge_tags_double_and_single_braces(self):
|
||||
from messaging.services import render_merge_tags
|
||||
|
||||
contact = Contact.objects.create(
|
||||
email="pat@example.com",
|
||||
first_name="Pat",
|
||||
last_name="Lee",
|
||||
phone="6305551212",
|
||||
)
|
||||
text = "Hi {{first_name}} {{last_name}} / {first_name} {email}"
|
||||
out = render_merge_tags(text, contact)
|
||||
self.assertEqual(out, "Hi Pat Lee / Pat pat@example.com")
|
||||
|
||||
def test_email_send_substitutes_merge_tags(self):
|
||||
from django.core import mail
|
||||
|
||||
from messaging.providers.email.smtp2go import send_email
|
||||
from messaging.services import create_campaign_draft, set_channel_consent
|
||||
|
||||
User = get_user_model()
|
||||
user = User.objects.create_user(username="merge", password="x")
|
||||
contact = Contact.objects.create(
|
||||
email="pat@example.com", first_name="Pat", last_name="Lee"
|
||||
)
|
||||
set_channel_consent(contact, Channel.EMAIL, opted_in=True, reason="test")
|
||||
campaign = create_campaign_draft(
|
||||
name="Merge",
|
||||
audience=Campaign.Audience.EMAIL_OPT_IN,
|
||||
subject="Hello {{first_name}}",
|
||||
body="<p>Dear {{first_name}} {{last_name}}</p>",
|
||||
created_by=user,
|
||||
)
|
||||
send_email(campaign.messages.get())
|
||||
self.assertEqual(mail.outbox[0].subject, "Hello Pat")
|
||||
html = mail.outbox[0].alternatives[0][0]
|
||||
self.assertIn("Dear Pat Lee", html)
|
||||
self.assertNotIn("{{first_name}}", html)
|
||||
|
||||
|
||||
class CampaignRecipientTableTests(TestCase):
|
||||
def setUp(self):
|
||||
from messaging.services import create_campaign_draft, set_channel_consent
|
||||
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(
|
||||
username="recip", password="test-pass-123"
|
||||
)
|
||||
self.client = Client()
|
||||
self.client.login(username="recip", password="test-pass-123")
|
||||
self.contacts = []
|
||||
for i in range(3):
|
||||
c = Contact.objects.create(
|
||||
email=f"c{i}@example.com", first_name=f"Name{i}"
|
||||
)
|
||||
set_channel_consent(c, Channel.EMAIL, opted_in=True, reason="test")
|
||||
self.contacts.append(c)
|
||||
self.campaign = create_campaign_draft(
|
||||
name="Recipients",
|
||||
audience=Campaign.Audience.EMAIL_OPT_IN,
|
||||
subject="Hi",
|
||||
body="Body",
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
def test_detail_does_not_flash_message_objects(self):
|
||||
url = reverse(
|
||||
"messaging:campaign_detail", kwargs={"pk": self.campaign.pk}
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, "email →")
|
||||
self.assertContains(response, "Recipients")
|
||||
self.assertContains(response, "Remove")
|
||||
|
||||
def test_remove_recipient(self):
|
||||
msg = self.campaign.messages.first()
|
||||
url = reverse(
|
||||
"messaging:campaign_message_remove",
|
||||
kwargs={"pk": self.campaign.pk, "message_id": msg.pk},
|
||||
)
|
||||
response = self.client.post(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(self.campaign.messages.count(), 2)
|
||||
|
||||
def test_postcard_shows_pcm_events_title(self):
|
||||
from messaging.services import create_campaign_draft
|
||||
|
||||
Contact.objects.create(
|
||||
email="pc@example.com",
|
||||
postal_address=Contact.make_postal_address(line1="1 Main"),
|
||||
)
|
||||
campaign = create_campaign_draft(
|
||||
name="Cards",
|
||||
audience=Campaign.Audience.POSTCARD_OPT_IN,
|
||||
body="Postcard mailing",
|
||||
created_by=self.user,
|
||||
template=MessageTemplate.objects.create(
|
||||
name="Design",
|
||||
channel=Channel.POSTCARD,
|
||||
body="",
|
||||
postcard_front={"design_id": "99"},
|
||||
),
|
||||
)
|
||||
url = reverse("messaging:campaign_detail", kwargs={"pk": campaign.pk})
|
||||
response = self.client.get(url)
|
||||
self.assertContains(response, "Recent PCM Integrations events")
|
||||
self.assertNotContains(response, "Recent SMTP2GO events")
|
||||
|
||||
Reference in New Issue
Block a user