diff --git a/rero_ils/modules/items/api/circulation.py b/rero_ils/modules/items/api/circulation.py index f137fda4a1..03a79bb2fb 100644 --- a/rero_ils/modules/items/api/circulation.py +++ b/rero_ils/modules/items/api/circulation.py @@ -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 diff --git a/rero_ils/modules/libraries/api.py b/rero_ils/modules/libraries/api.py index 4aed092b24..1e0c5a61af 100644 --- a/rero_ils/modules/libraries/api.py +++ b/rero_ils/modules/libraries/api.py @@ -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(): @@ -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 diff --git a/tests/api/circulation/test_library_with_no_circulation.py b/tests/api/circulation/test_library_with_no_circulation.py new file mode 100644 index 0000000000..13b8ce3062 --- /dev/null +++ b/tests/api/circulation/test_library_with_no_circulation.py @@ -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 . + +"""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 diff --git a/tests/api/libraries/test_libraries_rest.py b/tests/api/libraries/test_libraries_rest.py index ea47bce5d3..d67a16b770 100644 --- a/tests/api/libraries/test_libraries_rest.py +++ b/tests/api/libraries/test_libraries_rest.py @@ -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): diff --git a/tests/data/data.json b/tests/data/data.json index 7f06b0d1b9..a99167337f 100644 --- a/tests/data/data.json +++ b/tests/data/data.json @@ -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", @@ -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", @@ -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", diff --git a/tests/fixtures/metadata.py b/tests/fixtures/metadata.py index 5fe26f1525..3ade91e0c5 100644 --- a/tests/fixtures/metadata.py +++ b/tests/fixtures/metadata.py @@ -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.""" @@ -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.""" diff --git a/tests/fixtures/organisations.py b/tests/fixtures/organisations.py index a56d91af83..7076c5a055 100644 --- a/tests/fixtures/organisations.py +++ b/tests/fixtures/organisations.py @@ -86,6 +86,12 @@ def lib_martigny_data(data): return deepcopy(data.get('lib1')) +@pytest.fixture(scope="module") +def lib_martigny_bourg_data(data): + """Martigny-bourg library data.""" + return deepcopy(data.get('lib7')) + + @pytest.fixture(scope="module") def lib_martigny(app, org_martigny, lib_martigny_data): """Martigny-ville library.""" @@ -98,6 +104,18 @@ def lib_martigny(app, org_martigny, lib_martigny_data): return lib +@pytest.fixture(scope="module") +def lib_martigny_bourg(app, org_martigny, lib_martigny_bourg_data): + """Martigny-bourg library.""" + lib = Library.create( + data=lib_martigny_bourg_data, + delete_pid=False, + dbcommit=True, + reindex=True) + flush_index(LibrariesSearch.Meta.index) + return lib + + @pytest.fixture(scope="module") def lib_saillon_data(data): """Saillon library data.""" @@ -194,6 +212,12 @@ def loc_public_martigny_data(data): return deepcopy(data.get('loc1')) +@pytest.fixture(scope="module") +def loc_public_martigny_bourg_data(data): + """Load public space location for Martigny bourg.""" + return deepcopy(data.get('loc15')) + + @pytest.fixture(scope="module") def loc_public_saillon_data(data): """Load public space location for Saillon.""" @@ -302,6 +326,19 @@ def loc_public_martigny(app, lib_martigny, loc_public_martigny_data): return loc +@pytest.fixture(scope="module") +def loc_public_martigny_bourg( + app, lib_martigny_bourg, loc_public_martigny_bourg_data): + """Create public space location for Martigny bourg.""" + loc = Location.create( + data=loc_public_martigny_bourg_data, + delete_pid=False, + dbcommit=True, + reindex=True) + flush_index(LocationsSearch.Meta.index) + return loc + + @pytest.fixture(scope="module") def loc_public_saillon(app, lib_saillon, loc_public_saillon_data): """Create public space location for saillon."""