From a5723857acd978f162ed4099d8667eba98ee591f Mon Sep 17 00:00:00 2001 From: Evan Chen Date: Fri, 13 Dec 2024 15:31:43 -0500 Subject: [PATCH] fix(roster): no 1st pay after one_semester_date For invoices created after self.semester.one_semester_date there shouldn't be any first_payment_deadline --- roster/models.py | 18 ++++++++++++------ roster/tests.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/roster/models.py b/roster/models.py index 11e70969..624e4dc8 100644 --- a/roster/models.py +++ b/roster/models.py @@ -279,11 +279,11 @@ def payment_status(self): 0: student is clear (no invoice exists or total owed is nonpositive) 1: remind of upcoming payment for initial deadline 2: warn of late payment for initial deadline - 3: lock late payment for initial deadline + 3: lock late payment for initial deadline (more than 1 week past) 4: no warning yet, but student has something owed 5: remind of upcoming payment for primary deadline 6: warn of late payment for primary deadline - 7: lock late payment for primary deadline + 7: lock late payment for primary deadline (more than 1 week past) """ if self.semester.show_invoices is False: return 0 @@ -298,10 +298,17 @@ def payment_status(self): now = localtime() - first_payment_deadline = self.semester.first_payment_deadline + if ( + self.semester.one_semester_date is not None + and self.semester.most_payment_deadline + and invoice.created_at > self.semester.one_semester_date + ): + initial_payment_deadline = self.semester.most_payment_deadline + else: + initial_payment_deadline = self.semester.first_payment_deadline - if first_payment_deadline is not None and invoice.total_paid <= 0: - d = max(invoice.created_at, first_payment_deadline) - now + if initial_payment_deadline is not None and invoice.total_paid <= 0: + d = max(invoice.created_at, initial_payment_deadline) - now if d < timedelta(days=-7): return 3 elif d < timedelta(days=0): @@ -310,7 +317,6 @@ def payment_status(self): return 1 most_payment_deadline = self.semester.most_payment_deadline - if ( most_payment_deadline is not None and invoice.total_paid < 2 * invoice.total_cost / 3 diff --git a/roster/tests.py b/roster/tests.py index fbd48170..b84aa9b2 100644 --- a/roster/tests.py +++ b/roster/tests.py @@ -236,6 +236,47 @@ def test_delinquency(self) -> None: self.assertEqual(bob.payment_status, 7) self.assertTrue(bob.is_delinquent) + def test_delinquency_for_joining_second_semester(self) -> None: + semester: Semester = SemesterFactory.create( + show_invoices=True, + first_payment_deadline=datetime.datetime(2022, 9, 21, tzinfo=UTC), + most_payment_deadline=datetime.datetime(2023, 1, 21, tzinfo=UTC), + one_semester_date=datetime.datetime(2022, 12, 30, tzinfo=UTC), + ) + + alice: Student = StudentFactory.create(semester=semester) + bob: Student = StudentFactory.create(semester=semester) + self.assertEqual(alice.payment_status, 0) # because no invoice exists + self.assertEqual(bob.payment_status, 0) # because no invoice exists + with freeze_time("2022-08-05", tz_offset=0): + InvoiceFactory.create(student=alice, preps_taught=2) + with freeze_time("2023-01-01", tz_offset=0): + InvoiceFactory.create(student=bob, preps_taught=1) + + with freeze_time("2023-01-02", tz_offset=0): + self.assertEqual(alice.payment_status, 3) + self.assertTrue(alice.is_delinquent) + self.assertEqual(bob.payment_status, 4) + self.assertFalse(bob.is_delinquent) + + with freeze_time("2023-01-20", tz_offset=0): + self.assertEqual(alice.payment_status, 3) + self.assertTrue(alice.is_delinquent) + self.assertEqual(bob.payment_status, 1) + self.assertFalse(bob.is_delinquent) + + with freeze_time("2023-01-25", tz_offset=0): + self.assertEqual(alice.payment_status, 3) + self.assertTrue(alice.is_delinquent) + self.assertEqual(bob.payment_status, 2) + self.assertFalse(bob.is_delinquent) + + with freeze_time("2023-01-30", tz_offset=0): + self.assertEqual(alice.payment_status, 3) + self.assertTrue(alice.is_delinquent) + self.assertEqual(bob.payment_status, 3) + self.assertTrue(bob.is_delinquent) + def test_student_properties(self) -> None: alice: Student = StudentFactory.create() units: list[Unit] = UnitFactory.create_batch(10)