Skip to content

Commit

Permalink
Add support for yearly schedules
Browse files Browse the repository at this point in the history
  • Loading branch information
norkans7 committed Jan 8, 2025
1 parent 08b1212 commit 3fb2462
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
27 changes: 27 additions & 0 deletions temba/schedules/migrations/0029_alter_schedule_repeat_period.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.1.2 on 2025-01-08 09:50

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("schedules", "0028_squashed"),
]

operations = [
migrations.AlterField(
model_name="schedule",
name="repeat_period",
field=models.CharField(
choices=[
("O", "Never"),
("D", "Daily"),
("W", "Weekly"),
("M", "Monthly"),
("Y", "Yearly"),
],
max_length=1,
),
),
]
16 changes: 16 additions & 0 deletions temba/schedules/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ class Schedule(models.Model):
REPEAT_DAILY = "D"
REPEAT_WEEKLY = "W"
REPEAT_MONTHLY = "M"
REPEAT_YEARLY = "Y"
REPEAT_CHOICES = (
(REPEAT_NEVER, _("Never")),
(REPEAT_DAILY, _("Daily")),
(REPEAT_WEEKLY, _("Weekly")),
(REPEAT_MONTHLY, _("Monthly")),
(REPEAT_YEARLY, _("Yearly")),
)

REPEAT_DAYS_CHOICES = (
Expand Down Expand Up @@ -169,6 +171,15 @@ def calculate_next_fire(self, now):
)

return next_fire
elif self.repeat_period == Schedule.REPEAT_YEARLY:
while next_fire <= now:
next_fire = (
(next_fire.astimezone(tzone.utc) + relativedelta(years=1))
.astimezone(tz)
.replace(hour=hour, minute=minute)
)

return next_fire

def get_repeat_days_display(self):
return [Schedule.DAYS_OF_WEEK_DISPLAY[d] for d in self.repeat_days_of_week] if self.repeat_days_of_week else []
Expand All @@ -184,6 +195,11 @@ def get_display(self):
return _("each week on %(daysofweek)s" % {"daysofweek": ", ".join(days)})
elif self.repeat_period == self.REPEAT_MONTHLY:
return _("each month on the %(dayofmonth)s" % {"dayofmonth": ordinal(self.repeat_day_of_month)})
elif self.repeat_period == self.REPEAT_YEARLY:
return _(
"each year on %(month)s %(day)s"
% {"month": self.next_fire.strftime("%B"), "day": ordinal(self.next_fire.strftime("%d"))}
)

@staticmethod
def _day_of_week(d):
Expand Down
18 changes: 18 additions & 0 deletions temba/schedules/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ def test_schedules(self):
],
display="each month on the 31st",
),
dict(
label="yearly repeating starting in the future",
trigger_date=datetime(2013, 1, 3, hour=10),
now=datetime(2013, 1, 3, hour=9),
repeat_period=Schedule.REPEAT_YEARLY,
first=datetime(2013, 1, 3, hour=10),
next=[datetime(2014, 1, 3, hour=10), datetime(2015, 1, 3, hour=10)],
display="each year on January 3rd",
),
dict(
label="yearly repeating starting in the past",
trigger_date=datetime(2013, 1, 3, hour=8),
now=datetime(2013, 1, 3, hour=9),
repeat_period=Schedule.REPEAT_YEARLY,
first=datetime(2014, 1, 3, hour=8),
next=[datetime(2015, 1, 3, hour=8), datetime(2016, 1, 3, hour=8)],
display="each year on January 3rd",
),
]

for tc in tcs:
Expand Down

0 comments on commit 3fb2462

Please sign in to comment.