Skip to content

Commit

Permalink
circulation: manage non-circulating libraries
Browse files Browse the repository at this point in the history
With this commit, for libraries with no pickup locations
the system considers the first library location as transaction
location for circulation transactions.

* Allows requests on items of non-circulating libraries at external locations.
* Closes rero#2367
* Adds a non-circulating library to units testing.

Co-Authored-by: Aly Badr <aly.badr@rero.ch>
  • Loading branch information
Aly Badr committed Oct 1, 2021
1 parent dd87109 commit 9d1cbb8
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 3 deletions.
2 changes: 1 addition & 1 deletion rero_ils/modules/items/api/circulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def complete_action_missing_params(
if transaction_library_pid is not None:
lib = Library.get_record_by_pid(transaction_library_pid)
kwargs['transaction_location_pid'] = \
lib.get_pickup_location_pid()
lib.get_transaction_location_pid()

return loan, kwargs

Expand Down
12 changes: 12 additions & 0 deletions rero_ils/modules/libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ def pickup_location_query(self):
'term', library__pid=self.pid).filter(
'term', is_pickup=True).source(['pid']).scan()

def transaction_locations_query(self):
"""Search the location index for a transaction location."""
return LocationsSearch().filter(
'term', library__pid=self.pid).source(['pid']).scan()

def get_pickup_locations_pids(self):
"""Returns libraries all pickup locations pids."""
for location in self.pickup_location_query():
Expand All @@ -117,6 +122,13 @@ def get_pickup_location_pid(self):
except StopIteration:
return None

def get_transaction_location_pid(self):
"""Returns libraries first transaction location pid."""
try:
return next(self.pickup_location_query()).pid
except StopIteration:
return next(self.transaction_locations_query()).pid

def _is_betweentimes(self, time_to_test, times):
"""Test if time is between times."""
times_open = False
Expand Down
43 changes: 43 additions & 0 deletions tests/api/circulation/test_library_with_no_circulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2020 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Tests REST checkout API methods in library with no circulation."""

from invenio_accounts.testutils import login_user_via_session
from utils import postdata


def test_requesting_item_from_non_circulating_library(
client, librarian_martigny, lib_martigny, lib_martigny_bourg,
patron_martigny, loc_public_martigny, loc_public_martigny_bourg,
item_lib_martigny_bourg, circulation_policies, patron2_martigny):
"""Test requests at non circulating library."""
# TEST: a librarian from an external library can request and item from a
# non circulation library to be picked-up at his own library.
login_user_via_session(client, librarian_martigny.user)
res, data = postdata(
client,
'api_item.librarian_request',
dict(
item_pid=item_lib_martigny_bourg.pid,
patron_pid=patron_martigny.pid,
pickup_location_pid=loc_public_martigny.pid,
transaction_library_pid=lib_martigny_bourg.pid,
transaction_user_pid=librarian_martigny.pid
)
)
assert res.status_code == 200
9 changes: 7 additions & 2 deletions tests/api/libraries/test_libraries_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,14 @@ def test_libraries_post_put_delete(client, lib_martigny_data, json_header):
assert res.status_code == 410


def test_library_no_pickup(lib_sion):
"""Test library with no pick_up location."""
def test_non_circulating_libraries(
lib_sion, lib_martigny, lib_martigny_bourg, loc_public_martigny,
loc_public_martigny_bourg):
"""Test pickup vs transaction locations."""
assert not lib_sion.get_pickup_location_pid()
assert not lib_martigny_bourg.get_pickup_location_pid()
assert lib_martigny.get_pickup_location_pid()
assert lib_martigny_bourg.get_transaction_location_pid()


def test_library_never_open(lib_sion):
Expand Down
183 changes: 183 additions & 0 deletions tests/data/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,152 @@
],
"communication_language": "fre"
},
"lib7": {
"$schema": "https://bib.rero.ch/schemas/libraries/library-v0.0.1.json",
"address": "Ave de la gare, Martigny 1920",
"code": "MARTIGNYBOURG",
"email": "reroilstest+martignybourg@gmail.com",
"name": "Library of Martigny-bourg",
"organisation": {
"$ref": "https://bib.rero.ch/api/organisations/org1"
},
"pid": "lib7",
"opening_hours": [
{
"day": "monday",
"is_open": true,
"times": [
{
"start_time": "07:00",
"end_time": "19:00"
}
]
},
{
"day": "tuesday",
"is_open": true,
"times": [
{
"start_time": "07:00",
"end_time": "19:00"
}
]
},
{
"day": "wednesday",
"is_open": true,
"times": [
{
"start_time": "07:00",
"end_time": "19:00"
}
]
},
{
"day": "thursday",
"is_open": true,
"times": [
{
"start_time": "07:00",
"end_time": "19:00"
}
]
},
{
"day": "friday",
"is_open": true,
"times": [
{
"start_time": "07:00",
"end_time": "19:00"
}
]
},
{
"day": "saturday",
"is_open": false,
"times": []
},
{
"day": "sunday",
"is_open": false,
"times": []
}
],
"exception_dates": [
{
"end_date": "2019-01-06",
"is_open": false,
"start_date": "2018-12-22",
"title": "Vacances de No\u00ebl",
"repeat": {
"interval": 1,
"period": "yearly"
}
},
{
"is_open": true,
"start_date": "2018-12-15",
"times": [
{
"end_time": "16:00",
"start_time": "10:00"
}
],
"title": "Samedi du livre"
},
{
"is_open": false,
"repeat": {
"interval": 1,
"period": "yearly"
},
"start_date": "2019-08-01",
"title": "1er ao\u00fbt"
},
{
"is_open": false,
"repeat": {
"interval": 2,
"period": "monthly"
},
"start_date": "2019-01-01",
"title": "1er du mois, 1 mois sur 2"
}
],
"notification_settings": [
{
"type": "due_soon",
"email": "reroilstest+martignybourg@gmail.com"
},
{
"type": "overdue",
"email": "reroilstest+martignybourg@gmail.com"
},
{
"type": "recall",
"email": "reroilstest+martignybourg@gmail.com"
},
{
"type": "availability",
"email": "reroilstest+martignybourg@gmail.com",
"delay": 0
},
{
"type": "request",
"email": "reroilstest+martignybourg@gmail.com"
},
{
"type": "transit_notice",
"email": "reroilstest+martignybourg@gmail.com"
},
{
"type": "booking",
"email": "reroilstest+martignybourg@gmail.com"
}
],
"communication_language": "fre"
},
"loc1": {
"$schema": "https://bib.rero.ch/schemas/locations/location-v0.0.1.json",
"code": "MARTIGNY-PUBLIC",
Expand Down Expand Up @@ -965,6 +1111,17 @@
"pickup_name": "SAILLON-PUBLIC: Public Space",
"allow_request": true
},
"loc15": {
"$schema": "https://bib.rero.ch/schemas/locations/location-v0.0.1.json",
"code": "MARTIGNY-BOURG-PUBLIC",
"name": "Martigny Bourg Library Public Space",
"pid": "loc15",
"library": {
"$ref": "https://bib.rero.ch/api/libraries/lib7"
},
"is_pickup": false,
"allow_request": true
},
"itty1": {
"$schema": "https://bib.rero.ch/schemas/item_types/item_type-v0.0.1.json",
"name": "standard",
Expand Down Expand Up @@ -3262,6 +3419,32 @@
},
"status": "on_shelf"
},
"item10": {
"$schema": "https://bib.rero.ch/schemas/items/item-v0.0.1.json",
"pid": "item10",
"barcode": "123410",
"type": "standard",
"document": {
"$ref": "https://bib.rero.ch/api/documents/doc1"
},
"call_number": "000010",
"location": {
"$ref": "https://bib.rero.ch/api/locations/loc15"
},
"library": {
"$ref": "https://bib.rero.ch/api/libraries/lib7"
},
"organisation": {
"$ref": "https://bib.rero.ch/api/organisations/org1"
},
"item_type": {
"$ref": "https://bib.rero.ch/api/item_types/itty1"
},
"status": "on_shelf",
"url": "https://lipda.mediatheque.ch/CH-000019-X:223156.file",
"pac_code": "0_frozen_collection",
"price": 15.2
},
"ptrn1": {
"$schema": "https://bib.rero.ch/schemas/patrons/patron-v0.0.1.json",
"pid": "ptrn1",
Expand Down
23 changes: 23 additions & 0 deletions tests/fixtures/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ def item_lib_martigny_data(data):
return deepcopy(data.get('item1'))


@pytest.fixture(scope="module")
def item_lib_martigny_bourg_data(data):
"""Load item of martigny bourg library."""
return deepcopy(data.get('item10'))


@pytest.fixture(scope="function")
def item_lib_martigny_data_tmp(data):
"""Load item of martigny library scope function."""
Expand All @@ -433,6 +439,23 @@ def item_lib_martigny(
return item


@pytest.fixture(scope="module")
def item_lib_martigny_bourg(
app,
document,
item_lib_martigny_bourg_data,
loc_public_martigny_bourg,
item_type_standard_martigny):
"""Create item of martigny library bourg."""
item = Item.create(
data=item_lib_martigny_bourg_data,
delete_pid=False,
dbcommit=True,
reindex=True)
flush_index(ItemsSearch.Meta.index)
return item


@pytest.fixture(scope="module")
def item2_lib_martigny_data(data):
"""Load item of martigny library."""
Expand Down
Loading

0 comments on commit 9d1cbb8

Please sign in to comment.