Skip to content

Commit

Permalink
invenio: upgrade to invenio circulation v1.0.0a21
Browse files Browse the repository at this point in the history
This PR does not address the units testing and json data files changes.

* Adapts reroils config files.

Co-Authored-by: Aly Badr <aly.badr@rero.ch>
  • Loading branch information
Aly Badr committed Aug 4, 2020
1 parent ba7e58f commit 20ade4b
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 40 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Flask-BabelEx = ">=0.9.3"

## Third party invenio modules used by RERO ILS
invenio-oaiharvester = {tag = "v1.0.0a4", git = "https://github.com/inveniosoftware/invenio-oaiharvester.git"}
invenio-circulation = {tag = "v1.0.0a16", git = "https://github.com/inveniosoftware/invenio-circulation.git"}
invenio-circulation = {tag = "v1.0.0a21", git = "https://github.com/inveniosoftware/invenio-circulation.git"}

## Invenio 3.2.1 base modules used by RERO ILS
# same as invenio metadata extras without invenio-search-ui
Expand Down Expand Up @@ -55,6 +55,7 @@ pycountry = ">=19.7.15"
xmltodict = "*"
redisbeat = "*"
jsonpickle = "*"
ciso8601 = "*"
# TODO: to be removed when the thumbnail will be refactored
angular-gettext-babel= ">=0.1"

Expand Down Expand Up @@ -83,7 +84,6 @@ check-manifest = ">=0.35"
coverage = ">=4.5.3"
isort = ">=4.3"
mock = ">=2.0.0"
marshmallow = ">=2.15.1,<3.0.0"
pydocstyle = ">=3.0.0"
# TODO: Delete 6.0.0 limitation when pytest_pep8 will use Pep8Item.from_parent
# Cf. https://bitbucket.org/pytest-dev/pytest-pep8/issues/25/pep8item-should-use-from_parent-method
Expand Down
18 changes: 12 additions & 6 deletions rero_ils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from invenio_circulation.transitions.transitions import CreatedToPending, \
ItemAtDeskToItemOnLoan, ItemOnLoanToItemInTransitHouse, \
ItemOnLoanToItemOnLoan, PendingToItemAtDesk, \
PendingToItemInTransitPickup, ToItemOnLoan
PendingToItemInTransitPickup, ToItemOnLoan, ToCancelled
from invenio_records_rest.utils import deny_all

from .modules.acq_accounts.api import AcqAccount
Expand Down Expand Up @@ -1829,6 +1829,12 @@ def _(x):

CIRCULATION_DOCUMENT_EXISTS = Document.get_record_by_pid
CIRCULATION_ITEM_REF_BUILDER = Loan.loan_build_item_ref
CIRCULATION_PATRON_REF_BUILDER = Loan.loan_build_patron_ref
CIRCULATION_DOCUMENT_REF_BUILDER = Loan.loan_build_document_ref
CIRCULATION_TRANSACTION_LOCATION_VALIDATOR = \
Location.transaction_location_validator
CIRCULATION_TRANSACTION_USER_VALIDATOR = \
Patron.transaction_user_validator

# This is needed for absolute URL (url_for)
# SERVER_NAME = 'localhost:5000'
Expand Down Expand Up @@ -1892,19 +1898,19 @@ def _(x):
transition=PendingToItemInTransitPickup,
trigger='validate_request'),
dict(dest='ITEM_ON_LOAN', transition=ToItemOnLoan, trigger='checkout'),
dict(dest='CANCELLED', trigger='cancel')
dict(dest='CANCELLED', trigger='cancel', transition=ToCancelled)
],
'ITEM_AT_DESK': [
dict(
dest='ITEM_ON_LOAN',
transition=ItemAtDeskToItemOnLoan,
trigger='checkout'
),
dict(dest='CANCELLED', trigger='cancel')
dict(dest='CANCELLED', trigger='cancel', transition=ToCancelled)
],
'ITEM_IN_TRANSIT_FOR_PICKUP': [
dict(dest='ITEM_AT_DESK', trigger='receive'),
dict(dest='CANCELLED', trigger='cancel')
dict(dest='CANCELLED', trigger='cancel', transition=ToCancelled)
],
'ITEM_ON_LOAN': [
dict(dest='ITEM_RETURNED',
Expand All @@ -1913,12 +1919,12 @@ def _(x):
transition=ItemOnLoanToItemInTransitHouse, trigger='checkin'),
dict(dest='ITEM_ON_LOAN', transition=ItemOnLoanToItemOnLoan,
trigger='extend'),
dict(dest='CANCELLED', trigger='cancel')
dict(dest='CANCELLED', trigger='cancel', transition=ToCancelled)
],
'ITEM_IN_TRANSIT_TO_HOUSE': [
dict(dest='ITEM_RETURNED',
transition=ItemInTransitHouseToItemReturned, trigger='receive'),
dict(dest='CANCELLED', trigger='cancel')
dict(dest='CANCELLED', trigger='cancel', transition=ToCancelled)
],
'ITEM_RETURNED': [],
'CANCELLED': [],
Expand Down
21 changes: 21 additions & 0 deletions rero_ils/modules/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from invenio_indexer.signals import before_record_index
from invenio_indexer.utils import _es7_expand_action
from invenio_pidstore.errors import PIDDoesNotExistError
from invenio_pidstore.ext import pid_exists
from invenio_pidstore.models import PersistentIdentifier, PIDStatus
from invenio_records.api import Record
from invenio_records_rest.utils import obj_or_import_string
Expand Down Expand Up @@ -196,6 +197,26 @@ def get_record_by_pid(cls, pid, with_deleted=False):
except PIDDoesNotExistError:
return None

@classmethod
def record_pid_exists(cls, pid):
"""Check if a persistent identifier exists.
:param pid: The PID value.
:returns: `True` if the PID exists.
"""
assert cls.provider
try:
PersistentIdentifier.get(
cls.provider.pid_type,
pid
)
return True

except NoResultFound:
return False
except PIDDoesNotExistError:
return False

@classmethod
def get_pid_by_id(cls, id):
"""Get pid by uuid."""
Expand Down
30 changes: 19 additions & 11 deletions rero_ils/modules/items/api/circulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
from functools import wraps

from flask import current_app
from invenio_circulation.api import get_loan_for_item, \
patron_has_active_loan_on_item
from invenio_circulation.api import get_loan_for_item
from invenio_circulation.search.api import search_by_patron_item_or_document

from invenio_circulation.errors import MissingRequiredParameterError, \
NoValidTransitionAvailableError
from invenio_circulation.proxies import current_circulation
Expand Down Expand Up @@ -111,7 +112,7 @@ def wrapper(item, *args, **kwargs):

# commit and reindex item and loans
current_search.flush_and_refresh(
current_circulation.loan_search.Meta.index)
current_circulation.loan_search_cls.Meta.index)
item.status_update(dbcommit=True, reindex=True, forceindex=True)
ItemsSearch.flush()
return item, action_applied
Expand Down Expand Up @@ -316,7 +317,7 @@ def dumps_for_circulation(self, sort_by=None):
@classmethod
def get_loans_by_item_pid(cls, item_pid):
"""Return any loan loans for item."""
results = current_circulation.loan_search.filter(
results = current_circulation.loan_search_cls.filter(
'term', item_pid=item_pid).source(includes='pid').scan()
for loan in results:
yield Loan.get_record_by_pid(loan.pid)
Expand Down Expand Up @@ -361,7 +362,7 @@ def get_pendings_loans(cls, library_pid=None, sort_by='transaction_date'):
if sort_by.startswith('-'):
sort_by = sort_by[1:]
order_by = 'desc'
search = current_circulation.loan_search\
search = current_circulation.loan_search_cls\
.source(['pid'])\
.params(preserve_order=True)\
.filter('term', state='PENDING')\
Expand All @@ -386,7 +387,7 @@ def get_checked_out_loans(
sort_by = sort_by[1:]
order_by = 'desc'

results = current_circulation.loan_search.source(['pid'])\
results = current_circulation.loan_search_cls.source(['pid'])\
.params(preserve_order=True)\
.filter('term', state='ITEM_ON_LOAN')\
.filter('term', patron_pid=patron_pid)\
Expand Down Expand Up @@ -577,10 +578,11 @@ def status_update(self, dbcommit=False, reindex=False, forceindex=False):

def item_has_active_loan_or_request(self):
"""Return True if active loan or a request found for item."""
item_object = {'value': self.pid, 'type': 'item'}
states = ['PENDING'] + \
current_app.config['CIRCULATION_STATES_LOAN_ACTIVE']
search = search_by_pid(
item_pid=self.pid,
item_pid=item_object,
filter_states=states,
)
search_result = search.execute()
Expand Down Expand Up @@ -705,10 +707,16 @@ def is_loaned_to_patron(self, patron_barcode):
"""Check if the item is loaned by a given patron."""
patron = Patron.get_patron_by_barcode(patron_barcode)
if patron:
patron_pid = patron.pid
checkout = patron_has_active_loan_on_item(patron_pid, self.pid)
if checkout:
return True
states = ['CREATED"', 'PENDING'] + \
current_app.config['CIRCULATION_STATES_LOAN_ACTIVE']
search = search_by_patron_item_or_document(
patron_pid=patron.pid,
item_pid=self.pid,
document_pid=self.document_pid,
filter_states=states,
)
search_result = search.execute()
return search_result.hits.total > 0
return False

@classmethod
Expand Down
42 changes: 35 additions & 7 deletions rero_ils/modules/loans/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class Loan(IlsRecord):
'item': 'item'
}
}
DATE_FIELDS = [
"start_date",
"end_date",
"request_expire_date",
"request_start_date",
]
DATETIME_FIELDS = ["transaction_date"]

def __init__(self, data, model=None):
"""Loan init."""
Expand Down Expand Up @@ -113,17 +120,38 @@ def attach_item_ref(self):
raise MissingRequiredParameterError(
description='item_pid missing from loan {0}'.format(
self.pid))
if self.loan_build_item_ref:
self['item'] = self.loan_build_item_ref(item_pid)
self['item'] = self.loan_build_item_ref(item_pid, self)

def loan_build_item_ref(self, item_pid):
def loan_build_item_ref(self, item_pid, loan):
"""Build $ref for the Item attached to the Loan."""
return {'$ref': '{base_url}/api/{doc_type}/{pid}'.format(
base_url=get_base_url(),
doc_type='items',
pid=item_pid
)}

def loan_build_patron_ref(self, patron_pid, loan):
"""Build $ref for the Patron attached to the Loan."""
base_url = current_app.config.get('RERO_ILS_APP_BASE_URL')
url_api = '{base_url}/api/{doc_type}/{pid}'
return {
'$ref': url_api.format(
base_url=base_url,
doc_type='patrons',
pid=patron_pid)
}

def loan_build_document_ref(self, document_pid, loan):
"""Build $ref for the Document attached to the Loan."""
base_url = current_app.config.get('RERO_ILS_APP_BASE_URL')
url_api = '{base_url}/api/{doc_type}/{pid}'
return {
'$ref': url_api.format(
base_url=base_url,
doc_type='documents',
pid=document_pid)
}

@classmethod
def _loan_build_org_ref(cls, data):
"""Build $ref for the organisation of the Loan."""
Expand Down Expand Up @@ -279,7 +307,7 @@ def get_request_by_item_pid_by_patron_pid(item_pid, patron_pid):

def get_loans_by_patron_pid(patron_pid):
"""Return all loans for patron."""
results = current_circulation.loan_search\
results = current_circulation.loan_search_cls\
.source(['pid'])\
.params(preserve_order=True)\
.filter('term', patron_pid=patron_pid)\
Expand Down Expand Up @@ -334,7 +362,7 @@ def patron_profile_loans(patron_pid):

def get_last_transaction_loc_for_item(item_pid):
"""Return last transaction location for an item."""
results = current_circulation.loan_search\
results = current_circulation.loan_search_cls\
.source(['pid'])\
.params(preserve_order=True)\
.filter('term', item_pid=item_pid)\
Expand All @@ -353,7 +381,7 @@ def get_due_soon_loans():
"""Return all due_soon loans."""
from .utils import get_circ_policy
due_soon_loans = []
results = current_circulation.loan_search\
results = current_circulation.loan_search_cls\
.source(['pid'])\
.params(preserve_order=True)\
.filter('term', state='ITEM_ON_LOAN')\
Expand All @@ -376,7 +404,7 @@ def get_overdue_loans():
"""Return all overdue loans."""
from .utils import get_circ_policy
overdue_loans = []
results = current_circulation.loan_search\
results = current_circulation.loan_search_cls\
.source(['pid'])\
.params(preserve_order=True)\
.filter('term', state='ITEM_ON_LOAN')\
Expand Down
55 changes: 46 additions & 9 deletions rero_ils/modules/loans/jsonschemas/loans/loan-ils-v0.0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@
}
}
},
"patron": {
"title": "Patron",
"type": "object",
"properties": {
"$ref": {
"title": "Patron URI",
"type": "string",
"pattern": "^https://ils.rero.ch/api/patrons/.+?$",
"default": "https://ils.rero.ch/api/patrons/"
}
}
},
"document": {
"title": "Document",
"type": "object",
"properties": {
"$ref": {
"title": "Document URI",
"type": "string",
"pattern": "^https://ils.rero.ch/api/documents/.+?$",
"default": "https://ils.rero.ch/api/documents/"
}
}
},
"extension_count": {
"type": "integer",
"title": "Loan extension count"
Expand All @@ -47,8 +71,16 @@
"title": "Document PID"
},
"item_pid": {
"type": "string",
"title": "Item PID"
"properties": {
"type": {
"type": "string"
},
"value": {
"type": "string"
}
},
"title": "Item ID",
"type": "object"
},
"transaction_user_pid": {
"type": "string",
Expand All @@ -62,21 +94,26 @@
"type": "string",
"title": "Request pickup location PID"
},
"request_expiry_date": {
"type": "string",
"format": "date-time",
"title": "Request expiry date"
},
"start_date": {
"type": "string",
"format": "date-time",
"format": "date",
"title": "Transaction start date"
},
"end_date": {
"type": "string",
"format": "date-time",
"format": "date",
"title": "Transaction end date"
},
"request_expire_date": {
"format": "date",
"title": "Request expire date",
"type": "string"
},
"request_start_date": {
"format": "date",
"title": "Request start date",
"type": "string"
},
"organisation": {
"title": "Organisation",
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion rero_ils/modules/loans/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def enrich_loan_data(sender, json=None, record=None, index=None,
:param doc_type: The doc_type for the record.
"""
if index == '-'.join(
[current_circulation.loan_search.Meta.index, doc_type]):
[current_circulation.loan_search_cls.Meta.index, doc_type]):
item = Item.get_record_by_pid(record.get('item_pid'))
json['library_pid'] = item.holding_library_pid

Expand Down
Loading

0 comments on commit 20ade4b

Please sign in to comment.