From 049c6ff1c7c4deabb5f82791e8adfe9d20edbfe6 Mon Sep 17 00:00:00 2001 From: Leonard Richardson Date: Thu, 1 Feb 2018 10:47:03 -0500 Subject: [PATCH] Only use the vendor value for Hold.end if it's in the future. --- model.py | 5 +++-- tests/test_model.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/model.py b/model.py index 5216c8f34..9c10a4181 100644 --- a/model.py +++ b/model.py @@ -883,8 +883,9 @@ def until(self, default_loan_period, default_reservation_period): this--the library's license might expire and then you'll _never_ get the book.) """ - if self.end: - # Whew, the server provided its own estimate. + if self.end and self.end > datetime.datetime.utcnow(): + # The license source provided their own estimate, and it's + # not obviously wrong, so use it. return self.end if default_reservation_period is None: diff --git a/tests/test_model.py b/tests/test_model.py index fbbc4b42d..2ec3e344e 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -4609,6 +4609,42 @@ def test_calculate_until(self): start, 10, 0, default_loan, default_reservation) eq_(e, None) + def test_vendor_hold_end_value_takes_precedence_over_calculated_value(self): + """If the vendor has provided an estimated availability time, + that is used in preference to the availability time we + calculate. + """ + now = datetime.datetime.utcnow() + tomorrow = now + datetime.timedelta(days=1) + + patron = self._patron() + pool = self._licensepool(edition=None) + hold, is_new = pool.on_hold_to(patron) + hold.position = 1 + hold.end = tomorrow + + default_loan = datetime.timedelta(days=1) + default_reservation = datetime.timedelta(days=2) + eq_(tomorrow, hold.until(default_loan, default_reservation)) + + calculated_value = hold._calculate_until( + now, hold.position, pool.licenses_available, + default_loan, default_reservation + ) + + # If the vendor value is not in the future, it's ignored + # and the calculated value is used instead. + def assert_calculated_value_used(): + result = hold.until(default_loan, default_reservation) + assert (result-calculated_value).seconds < 5 + hold.end = now + assert_calculated_value_used() + + # The calculated value is also used there is no + # vendor-provided value. + hold.end = None + assert_calculated_value_used() + class TestAnnotation(DatabaseTest): def test_set_inactive(self): pool = self._licensepool(None)