Skip to content

Commit

Permalink
circulation: renewal due date from current_date
Browse files Browse the repository at this point in the history
* NEW Calculates renewal due date from current date instead of checkout due date.
* NEW Removes renewal from the list of possible actions if renewal due date less than checkout due date.
* FIX Fixes #231.

Signed-off-by: Aly Badr <aly.badr@rero.ch>
  • Loading branch information
Aly Badr authored and jma committed May 27, 2019
1 parent 893aaf5 commit 817ca62
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 52 deletions.
14 changes: 8 additions & 6 deletions rero_ils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from __future__ import absolute_import, print_function

from datetime import timedelta
from functools import partial

from invenio_circulation.pidstore.pids import CIRCULATION_LOAN_FETCHER, \
CIRCULATION_LOAN_MINTER, CIRCULATION_LOAN_PID_TYPE
Expand All @@ -51,9 +52,8 @@
from rero_ils.modules.loans.api import Loan

from .modules.items.api import Item, ItemsIndexer
from .modules.loans.utils import can_be_requested, \
get_default_extension_duration, get_default_extension_max_count, \
get_default_loan_duration, is_item_available_for_checkout, \
from .modules.loans.utils import can_be_requested, get_default_loan_duration, \
get_extension_params, is_item_available_for_checkout, \
loan_satisfy_circ_policies
from .modules.patrons.api import Patron
from .permissions import librarian_delete_permission_factory, \
Expand Down Expand Up @@ -975,9 +975,11 @@ def _(x):
item_available=is_item_available_for_checkout
),
extension=dict(
from_end_date=True,
duration_default=get_default_extension_duration,
max_count=get_default_extension_max_count
from_end_date=False,
duration_default=partial(
get_extension_params, parameter_name='duration_default'),
max_count=partial(
get_extension_params, parameter_name='max_count'),
),
request=dict(
can_be_requested=can_be_requested
Expand Down
33 changes: 32 additions & 1 deletion rero_ils/modules/items/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,36 @@ def library_pid(self):
location = Location.get_record_by_pid(self.location_pid).replace_refs()
return location.get('library').get('pid')

def action_filter(self, action, loan):
"""Filter actions."""
from ..circ_policies.api import CircPolicy
from ..loans.utils import extend_loan_data_is_valid
patron_pid = loan.get('patron_pid')
patron_type_pid = Patron.get_record_by_pid(
patron_pid).replace_refs().patron_type_pid
circ_policy = CircPolicy.provide_circ_policy(
self.library_pid,
patron_type_pid,
self.item_type_pid
)
action_validated = True
if action == 'extend':
extension_count = loan.get('extension_count', 0)
if not (
circ_policy.get('number_renewals') > 0 and
extension_count < circ_policy.get('number_renewals') and
extend_loan_data_is_valid(
loan.get('end_date'),
circ_policy.get('renewal_duration'),
self.library_pid
)
):
action_validated = False
if action == 'checkout':
if not circ_policy.get('allow_checkout'):
action_validated = False
return action_validated

@property
def actions(self):
"""Get all available actions."""
Expand All @@ -375,7 +405,8 @@ def actions(self):
if loan:
for transition in transitions.get(loan.get('state')):
action = transition.get('trigger')
actions.add(action)
if self.action_filter(action, loan):
actions.add(action)
# default actions
if not loan:
for transition in transitions.get('CREATED'):
Expand Down
20 changes: 1 addition & 19 deletions rero_ils/modules/items/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from .api import Item
from ..circ_policies.api import CircPolicy
from ..loans.api import Loan
from ..loans.utils import extend_loan_data_is_valid
from ..patrons.api import Patron
from ...permissions import librarian_permission

Expand Down Expand Up @@ -244,27 +245,8 @@ def loans(patron_pid):
items_loans = Item.get_checked_out_items(patron_pid)
metadata = []
for item, loan in items_loans:
extension_count = loan.get('extension_count', 0)
item_dumps = item.dumps_for_circulation()
actions = item_dumps.get('actions')
circ_policy = CircPolicy.provide_circ_policy(
item.library_pid,
patron_type_pid,
item.item_type_pid
)
new_actions = []
for action in actions:
if action == 'checkout' and circ_policy.get('allow_checkout'):
new_actions.append(action)
if (
action == 'extend_loan' and
circ_policy.get('number_renewals') > 0 and
extension_count < circ_policy.get('number_renewals')
):
new_actions.append(action)
if action == 'checkin':
new_actions.append(action)
item_dumps['actions'] = new_actions
metadata.append({
'item': item_dumps,
'loan': loan.dumps_for_circulation()
Expand Down
56 changes: 39 additions & 17 deletions rero_ils/modules/loans/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

from datetime import datetime, timedelta

import ciso8601
from dateutil.parser import parse

from ..circ_policies.api import CircPolicy
from ..items.api import Item
from ..libraries.api import Library
Expand Down Expand Up @@ -66,27 +69,46 @@ def get_default_loan_duration(loan):
return new_duration.days


def get_default_extension_duration(loan):
"""Return extension duration in number of days."""
def get_extension_params(loan=None, parameter_name=None):
"""Return extension parameters."""
policy = get_circ_policy(loan)
# TODO: case when start_date is not sysdate.
start_date = datetime.now()
library_pid = Item.get_record_by_pid(loan.item_pid).library_pid
library = Library.get_record_by_pid(library_pid)
# invenio-circulation due_date.
due_date = start_date + timedelta(days=policy.get('renewal_duration'))
# rero_ils due_date, considering library opening_hours and exception_dates.
# next_open: -1 to check first the due date not the days.
open_after_due_date = library.next_open(date=due_date - timedelta(days=1))
new_duration = open_after_due_date - start_date
end_date = ciso8601.parse_datetime_as_naive(loan.get('end_date'))
params = {
'max_count': policy.get('number_renewals'),
'duration_default': policy.get('renewal_duration')
}
current_date = datetime.now()

return new_duration.days
library = Library.get_record_by_pid(
Item.get_record_by_pid(loan.item_pid).library_pid)

calculated_due_date = current_date + timedelta(
days=policy.get('renewal_duration'))

def get_default_extension_max_count(loan):
"""Return extensions max count."""
policy = get_circ_policy(loan)
return policy.get('number_renewals')
first_open_date = library.next_open(
date=calculated_due_date - timedelta(days=1))

if first_open_date.date() < end_date.date():
params['max_count'] = 0

new_duration = first_open_date - current_date
params['duration_default'] = new_duration.days

return params.get(parameter_name)


def extend_loan_data_is_valid(end_date, renewal_duration, library_pid):
"""Checks extend loan will be valid ."""
end_date = ciso8601.parse_datetime_as_naive(end_date)
current_date = datetime.now()
library = Library.get_record_by_pid(library_pid)
calculated_due_date = current_date + timedelta(
days=renewal_duration)
first_open_date = library.next_open(
date=calculated_due_date - timedelta(days=1))
if first_open_date.date() <= end_date.date():
return False
return True


def loan_satisfy_circ_policies(loan):
Expand Down
Loading

0 comments on commit 817ca62

Please sign in to comment.