Thanks to visit codestin.com
Credit goes to github.com

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
25 changes: 14 additions & 11 deletions rero_ils/modules/loans/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,17 @@ def get_circ_policy(loan, checkout_location=False):

def get_default_loan_duration(loan, initial_loan):
"""Return calculated checkout duration in number of days."""
# TODO: case when 'now' is not sysdate.
now = datetime.utcnow()
now_in_utc = datetime.now(timezone.utc)

# Get library (to check opening hours and get timezone)
library = Library.get_record_by_pid(loan.library_pid)

# Process difference between now and end of day in term of hours/minutes
# - use hours and minutes from now
# - check regarding end of day (eod), 23:59
# - correct the hours/date regarding library timezone
eod = timedelta(hours=23, minutes=59, seconds=00, milliseconds=000)
aware_eod = eod - library.get_timezone().utcoffset(now, is_dst=True)
time_to_eod = aware_eod - timedelta(hours=now.hour, minutes=now.minute)
now_in_library_timezone = now_in_utc.astimezone(tz=library.get_timezone())

# Due date should be defined differently from checkout_duration
# For that we use:
# - expected due date (now + checkout_duration)
# - we apply a -1 day correction because the next open day is not today
# - next library open date (the eve of expected due date is used)
# We finally make the difference between next library open date and now.
# We apply a correction for hour/minute to be 23:59 (end of day).
Expand All @@ -84,11 +78,20 @@ def get_default_loan_duration(loan, initial_loan):
# method. This was not the place for this ; this function should
# only return the loan duration.
policy = get_circ_policy(loan)
due_date_eve = now \
due_date_eve = now_in_library_timezone \
+ timedelta(days=policy.get('checkout_duration', 0)) \
- timedelta(days=1)
next_open_date = library.next_open(date=due_date_eve)
return timedelta(days=(next_open_date - now).days) + time_to_eod
# all libraries are closed at 23h59
# the next_open returns UTC.
end_date_in_library_timezone = next_open_date.astimezone(
library.get_timezone()).replace(
hour=23,
minute=59,
second=0,
microsecond=0
)
return end_date_in_library_timezone - now_in_library_timezone


def get_extension_params(loan=None, initial_loan=None, parameter_name=None):
Expand Down
65 changes: 62 additions & 3 deletions tests/ui/loans/test_loans_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ def test_loans_create(loan_pending_martigny):

def test_item_loans_default_duration(
item_lib_martigny, librarian_martigny, patron_martigny,
loc_public_martigny, circulation_policies):
loc_public_martigny, circulation_policies, lib_martigny):
"""Test default loan duration."""

# create a loan with request is easy
item, actions = item_lib_martigny.request(
pickup_location_pid=loc_public_martigny.pid,
patron_pid=patron_martigny.pid,
Expand All @@ -71,10 +72,68 @@ def test_item_loans_default_duration(
)
loan_pid = actions['request']['pid']
loan = Loan.get_record_by_pid(loan_pid)
# a new loan without transaction location
new_loan = deepcopy(loan)
del new_loan['transaction_location_pid']
assert get_default_loan_duration(new_loan, None) == \
get_default_loan_duration(loan, None)
# should have the same duration
with freeze_time():
assert get_default_loan_duration(new_loan, None) == \
get_default_loan_duration(loan, None)

policy = get_circ_policy(loan)
# the checkout duration should be enougth long
assert policy.get('checkout_duration', 0) > 3
# now in UTC
for now_str in [
# winter time
'2021-12-28 06:00:00', '2022-12-28 20:00:00',
# winter to summer time
'2022-03-22 06:00:00', '2022-03-22 20:00:00',
# summer time
'2022-06-28 05:00:00', '2022-06-28 19:00:00',
# summer to winter time
'2022-10-25 05:00:00', '2022-10-25 19:00:00'
]:
with freeze_time(now_str, tz_offset=0):
# get loan duration
duration = get_default_loan_duration(loan, None)
# now in datetime object
now = datetime.now(timezone.utc)
utc_end_date = now + duration
# computed end date at the library timezone
end_date = utc_end_date.astimezone(
tz=lib_martigny.get_timezone())
expected_utc_end_date = now + timedelta(
days=policy['checkout_duration'])
# expected end date at the library timezone
expected_end_date = expected_utc_end_date.astimezone(
lib_martigny.get_timezone())
assert end_date.strftime('%Y-%m-%d') == \
expected_end_date.strftime('%Y-%m-%d')
assert end_date.hour == 23
assert end_date.minute == 59

# test library closed days
now_str = '2022-02-04 14:00:00'
with freeze_time(now_str, tz_offset=0):
# get loan duration
duration = get_default_loan_duration(loan, None)
# now in datetime object
now = datetime.now(timezone.utc)

utc_end_date = now + duration
# computed end date at the library timezone
end_date = utc_end_date.astimezone(tz=lib_martigny.get_timezone())
# saturday and sunday is closed (+2)
expected_utc_end_date = now + timedelta(
days=(policy['checkout_duration'] + 2))
# expected end date at the library timezone
expected_end_date = expected_utc_end_date.astimezone(
lib_martigny.get_timezone())
assert end_date.strftime('%Y-%m-%d') == \
expected_end_date.strftime('%Y-%m-%d')
assert end_date.hour == 23
assert end_date.minute == 59
item_lib_martigny.cancel_item_request(
pid=loan.pid,
transaction_location_pid=loc_public_martigny.pid,
Expand Down