Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions adserver/migrations/0107_flight_auto_renew_notify_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.2.11 on 2026-03-03 01:17

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('adserver', '0106_add_advertiser_flight_logos'),
]

operations = [
migrations.AddField(
model_name='flight',
name='auto_renew_notify',
field=models.BooleanField(default=False, help_text='Whether the user has been notified of their flight renewal', verbose_name='Auto renew notification sent'),
),
migrations.AddField(
model_name='historicalflight',
name='auto_renew_notify',
field=models.BooleanField(default=False, help_text='Whether the user has been notified of their flight renewal', verbose_name='Auto renew notification sent'),
),
]
5 changes: 5 additions & 0 deletions adserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,11 @@ class Flight(TimeStampedModel, IndestructibleModel):
_("Automatically renew when complete"),
default=False,
)
auto_renew_notify = models.BooleanField(
_("Auto renew notification sent"),
default=False,
help_text=_("Whether the user has been notified of their flight renewal"),
)
auto_renew_payment_method = models.CharField(
_("Auto renewal payment method"),
max_length=100,
Expand Down
25 changes: 19 additions & 6 deletions adserver/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,17 +1033,27 @@ def notify_of_first_flight_launched():


@app.task()
def notify_of_autorenewing_flights(days_before=7):
def notify_of_autorenewing_flights(completion_threshold=80):
"""Send a note to flights set to renew automatically."""
# Flight must end in exactly `days_before` days
# to receive the notification
end_date = get_ad_day().date() + datetime.timedelta(days=days_before)

for flight in Flight.objects.filter(
live=True,
auto_renew=True,
end_date=end_date,
auto_renew_notify=False,
).select_related():
# Flight must be at least 80% complete to receive the notification
flight_duration_perc_complete = 0.0
flight_days = flight.sold_days()
if flight_days > 0:
flight_duration_perc_complete = (
max(0, flight_days - flight.days_remaining()) / flight_days * 100
)

if (
flight.percent_complete() < completion_threshold
or flight_duration_perc_complete < completion_threshold
):
continue

log.info("Notifying about flight %s auto-renewing", flight)
if settings.FRONT_ENABLED:
advertiser = flight.campaign.advertiser
Expand Down Expand Up @@ -1073,6 +1083,9 @@ def notify_of_autorenewing_flights(days_before=7):
message.draft = True # Only create a draft for now
message.send()

flight.auto_renew_notify = True
flight.save(update_fields=["auto_renew_notify"])


@app.task()
def notify_of_completed_flights():
Expand Down
25 changes: 24 additions & 1 deletion adserver/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,25 @@ def test_notify_of_autorenewing_flights(self):
# Shouldn't be any completed flight messages
self.assertEqual(len(mail.outbox), 0)

self.flight.end_date = get_ad_day().date() + datetime.timedelta(days=7)
# Set up flight to be 0% complete and auto renewing
self.flight.start_date = get_ad_day().date()
self.flight.end_date = get_ad_day().date() + datetime.timedelta(days=10)
self.flight.auto_renew = True
self.flight.sold_clicks = 100
self.flight.cpc = 1.0
self.flight.total_clicks = 0
self.flight.save()

# It is 0% complete, so no email should be sent
notify_of_autorenewing_flights()
self.assertEqual(len(mail.outbox), 0)
self.flight.refresh_from_db()
self.assertFalse(self.flight.auto_renew_notify)

# Move the start date back so it is 90% complete (9 days of 10 days elapsed)
self.flight.start_date = get_ad_day().date() - datetime.timedelta(days=9)
self.flight.end_date = get_ad_day().date() + datetime.timedelta(days=1)
self.flight.total_clicks = 90
self.flight.save()

notify_of_autorenewing_flights()
Expand All @@ -191,6 +208,12 @@ def test_notify_of_autorenewing_flights(self):
self.assertTrue(
mail.outbox[0].subject.startswith("Advertising flight renewing")
)
self.flight.refresh_from_db()
self.assertTrue(self.flight.auto_renew_notify)

# Calling again shouldn't send another email because auto_renew_notify is now True
notify_of_autorenewing_flights()
self.assertEqual(len(mail.outbox), 1)

@override_settings(
# Use the memory email backend instead of front for testing
Expand Down
Loading