Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
19 changes: 15 additions & 4 deletions hypha/apply/projects/reports/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,24 @@ def get_frequency_display(self):
)
next_report = self.current_due_report()

# current_due_report() only returns an existing pending report row and
# can be None (e.g. the project hasn't started yet, or the next report
# row hasn't been created). Fall back to the schedule anchor date, which
# is what a report's end_date derives from, so the displayed schedule is
# still correct.
reference_date = (
next_report.end_date
if next_report
else (self.schedule_start or self.project.proposed_start)
)

if self.frequency == self.YEAR:
if self.schedule_start and self.schedule_start.day == 31:
day_of_month = _("last day")
month = self.schedule_start.strftime("%B")
else:
day_of_month = ordinal(next_report.end_date.day)
month = next_report.end_date.strftime("%B")
day_of_month = ordinal(reference_date.day)
month = reference_date.strftime("%B")
if self.occurrence == 1:
return _("Once a year on {month} {day}").format(
day=day_of_month, month=month
Expand All @@ -299,14 +310,14 @@ def get_frequency_display(self):
if self.schedule_start and self.schedule_start.day == 31:
day_of_month = _("last day")
else:
day_of_month = ordinal(next_report.end_date.day)
day_of_month = ordinal(reference_date.day)
if self.occurrence == 1:
return _("Once a month on the {day}").format(day=day_of_month)
return _("Every {occurrence} months on the {day}").format(
occurrence=self.occurrence, day=day_of_month
)

weekday = next_report.end_date.strftime("%A")
weekday = reference_date.strftime("%A")

if self.occurrence == 1:
return _("Once a week on {weekday}").format(weekday=weekday)
Expand Down
35 changes: 35 additions & 0 deletions hypha/apply/projects/reports/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,41 @@ def test_submitted_report_unaffected(self):
next_report = config.current_due_report()
assert report != next_report

def test_frequency_display_without_pending_report_monthly(self):
"""get_frequency_display must not crash when no pending report row exists.

current_due_report() returns None in that case; the display should fall
back to the schedule_start anchor date.
"""
config = ReportConfigFactory(
disable_reporting=False,
frequency=ReportConfig.MONTH,
schedule_start=self.today.replace(day=15),
)
assert config.current_due_report() is None
assert config.get_frequency_display() == "Once a month on the 15th"

def test_frequency_display_without_pending_report_yearly(self):
config = ReportConfigFactory(
disable_reporting=False,
frequency=ReportConfig.YEAR,
schedule_start=self.today.replace(month=3, day=15),
)
assert config.current_due_report() is None
assert config.get_frequency_display() == "Once a year on March 15th"

def test_frequency_display_without_pending_report_weekly(self):
schedule_start = self.today.replace(day=15)
config = ReportConfigFactory(
disable_reporting=False,
frequency=ReportConfig.WEEK,
schedule_start=schedule_start,
)
assert config.current_due_report() is None
assert config.get_frequency_display() == "Once a week on {weekday}".format(
weekday=schedule_start.strftime("%A")
)

def test_past_due(self):
"""Test that past_due_reports includes overdue reports."""
report = ReportFactory(past_due=True)
Expand Down