-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle announcement emails from management command
refs: PV-901
- Loading branch information
Showing
12 changed files
with
155 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
parking_permits/management/commands/handle_announcement_emails.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from django.core.management.base import BaseCommand | ||
|
||
from parking_permits.cron import handle_announcement_emails | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Handle unhandled announcement emails." | ||
|
||
def handle(self, *args, **options): | ||
self.stdout.write(self.style.SUCCESS("Handling announcement emails.")) | ||
handle_announcement_emails() | ||
self.stdout.write(self.style.SUCCESS("Handled all announcement emails.")) |
18 changes: 18 additions & 0 deletions
18
parking_permits/migrations/0070_announcement_emails_handled.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 5.0.6 on 2024-12-10 09:50 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("parking_permits", "0069_orderitem_is_refunded"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="announcement", | ||
name="emails_handled", | ||
field=models.BooleanField(default=False, verbose_name="Emails handled"), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
from parking_permits import admin_resolvers | ||
from parking_permits.models import Announcement | ||
from parking_permits.models.parking_permit import ParkingPermitStatus | ||
from parking_permits.services.mail import send_announcement_email | ||
from parking_permits.services.mail import send_announcement_emails | ||
from parking_permits.tests.factories import ParkingZoneFactory | ||
from parking_permits.tests.factories.announcement import AnnouncementFactory | ||
from parking_permits.tests.factories.customer import CustomerFactory | ||
|
@@ -51,7 +51,6 @@ def test_happy_day_scenario(self, mock_post_create_announcement): | |
) | ||
|
||
self.assertDictEqual(message, {"success": True}) | ||
mock_post_create_announcement.assert_called_once() | ||
self.assertEqual(len(Announcement.objects.all()), 1) | ||
|
||
def test_should_set_correct_parking_zones(self, mock_post_create_announcement): | ||
|
@@ -71,148 +70,25 @@ def test_should_set_correct_parking_zones(self, mock_post_create_announcement): | |
self.assertEqual(len(announcement_zones), 2) | ||
self.assertEqual(announcement_zones[0], zone_a) | ||
self.assertEqual(announcement_zones[1], zone_b) | ||
|
||
|
||
@patch("parking_permits.admin_resolvers.send_announcement_email") | ||
class PostCreateAnnouncementTest(TestCase): | ||
def setUp(self): | ||
self.announcement = AnnouncementFactory() | ||
|
||
def test_should_have_no_customers_for_an_empty_parking_zone( | ||
self, mock_send_announcement_email: MagicMock | ||
): | ||
empty_zone = ParkingZoneFactory(name="Empty") | ||
self.announcement._parking_zones.set([empty_zone]) | ||
admin_resolvers.post_create_announcement(self.announcement) | ||
|
||
mock_send_announcement_email.assert_called_once() | ||
customers_arg = mock_send_announcement_email.call_args.args[0] | ||
self.assertEqual(len(customers_arg), 0) | ||
|
||
def test_should_get_correct_customers_from_single_parking_zone( | ||
self, mock_send_announcement_email: MagicMock | ||
): | ||
# Create zones A and B; A will be the target for our announcement. | ||
zone_a = ParkingZoneFactory(name="A") | ||
zone_b = ParkingZoneFactory(name="B") | ||
|
||
# Create customers for the zones. | ||
zone_a_customer = CustomerFactory(zone=zone_a) | ||
CustomerFactory(zone=zone_b) | ||
|
||
ParkingPermitFactory( | ||
customer=zone_a_customer, | ||
parking_zone=zone_a, | ||
status=ParkingPermitStatus.VALID, | ||
) | ||
|
||
# Set the announcement for zone A. | ||
self.announcement._parking_zones.set([zone_a]) | ||
|
||
admin_resolvers.post_create_announcement(self.announcement) | ||
|
||
# Should have only one customer (from zone A). | ||
mock_send_announcement_email.assert_called_once() | ||
customers_arg = mock_send_announcement_email.call_args.args[0] | ||
self.assertEqual(len(customers_arg), 1) | ||
filtered_customer = customers_arg.first() | ||
self.assertEqual(filtered_customer, zone_a_customer) | ||
|
||
def test_should_get_correct_customers_from_multiple_parking_zones( | ||
self, mock_send_announcement_email: MagicMock | ||
): | ||
# Create zones A, B and C; A and B will be the targets for our announcement. | ||
zone_a = ParkingZoneFactory(name="A") | ||
zone_b = ParkingZoneFactory(name="B") | ||
zone_c = ParkingZoneFactory(name="C") | ||
|
||
# Create customers for the zones. | ||
zone_a_customer = CustomerFactory(zone=zone_a) | ||
zone_b_customer = CustomerFactory(zone=zone_b) | ||
CustomerFactory(zone=zone_c) | ||
expected_customers = [zone_a_customer, zone_b_customer] | ||
|
||
ParkingPermitFactory( | ||
customer=zone_a_customer, | ||
parking_zone=zone_a, | ||
status=ParkingPermitStatus.VALID, | ||
) | ||
ParkingPermitFactory( | ||
customer=zone_b_customer, | ||
parking_zone=zone_b, | ||
status=ParkingPermitStatus.VALID, | ||
) | ||
|
||
# Set the announcement for zone A & B. | ||
self.announcement._parking_zones.set([zone_a, zone_b]) | ||
admin_resolvers.post_create_announcement(self.announcement) | ||
|
||
# Should have two customers (from zone A & B). | ||
mock_send_announcement_email.assert_called_once() | ||
customers_arg = mock_send_announcement_email.call_args.args[0] | ||
self.assertEqual(len(customers_arg), 2) | ||
for idx, customer in enumerate(customers_arg.order_by("zone__name")): | ||
self.assertEqual(customer, expected_customers[idx]) | ||
|
||
def test_should_get_correct_customers_only_with_valid_status( | ||
self, mock_send_announcement_email: MagicMock | ||
): | ||
# Create zones A, B and C. | ||
zone_a = ParkingZoneFactory(name="A") | ||
zone_b = ParkingZoneFactory(name="B") | ||
zone_c = ParkingZoneFactory(name="C") | ||
|
||
# Create customers for the zones. | ||
zone_a_customer = CustomerFactory(zone=zone_a) | ||
zone_b_customer = CustomerFactory(zone=zone_b) | ||
zone_c_customer = CustomerFactory(zone=zone_c) | ||
expected_customers = [zone_a_customer, zone_b_customer] | ||
|
||
# Create permits for the zones, but only A and B will be valid. | ||
ParkingPermitFactory( | ||
customer=zone_a_customer, | ||
parking_zone=zone_a, | ||
status=ParkingPermitStatus.VALID, | ||
) | ||
ParkingPermitFactory( | ||
customer=zone_b_customer, | ||
parking_zone=zone_b, | ||
status=ParkingPermitStatus.VALID, | ||
) | ||
ParkingPermitFactory( | ||
customer=zone_c_customer, | ||
parking_zone=zone_c, | ||
status=ParkingPermitStatus.DRAFT, | ||
) | ||
|
||
# Set the announcement for zone A, B & C. | ||
self.announcement._parking_zones.set([zone_a, zone_b, zone_c]) | ||
admin_resolvers.post_create_announcement(self.announcement) | ||
|
||
# Should have two customers (from zone A & B). | ||
mock_send_announcement_email.assert_called_once() | ||
customers_arg = mock_send_announcement_email.call_args.args[0] | ||
self.assertEqual(len(customers_arg), 2) | ||
for idx, customer in enumerate(customers_arg.order_by("zone__name")): | ||
self.assertEqual(customer, expected_customers[idx]) | ||
self.assertFalse(announcement_from_db.emails_handled) | ||
|
||
|
||
class SendAnnouncementMailTest(TestCase): | ||
def setUp(self): | ||
self.announcement = AnnouncementFactory() | ||
|
||
def test_should_do_nothing_if_no_customers(self): | ||
send_announcement_email([], self.announcement) | ||
send_announcement_emails([], self.announcement) | ||
self.assertEqual(len(mail.outbox), 0) | ||
|
||
def test_should_send_mail_for_a_single_customer(self): | ||
customer = CustomerFactory(email="[email protected]") | ||
send_announcement_email([customer], self.announcement) | ||
send_announcement_emails([customer], self.announcement) | ||
self.assertEqual(len(mail.outbox), 1) | ||
|
||
def test_should_send_mail_for_multiple_customers(self): | ||
customers = [CustomerFactory(email=f"foo{i}@bar.test") for i in range(1, 11)] | ||
send_announcement_email(customers, self.announcement) | ||
send_announcement_emails(customers, self.announcement) | ||
self.assertEqual(len(mail.outbox), 10) | ||
|
||
def test_mail_should_contain_all_translations(self): | ||
|
@@ -232,7 +108,7 @@ def test_mail_should_contain_all_translations(self): | |
subject_fi="Subject FI", | ||
subject_sv="Subject SV", | ||
) | ||
send_announcement_email([CustomerFactory()], announcement) | ||
send_announcement_emails([CustomerFactory()], announcement) | ||
sent_email = mail.outbox[0] | ||
html_body, content_type = sent_email.alternatives[0] | ||
|
||
|
Oops, something went wrong.