def test_checkout_temporary_item_type(client, librarian_martigny, lib_martigny, loc_public_martigny, patron_martigny, item_lib_martigny, item_type_on_site_martigny, circ_policy_short_martigny, circ_policy_default_martigny): """Test checkout or item with temporary item_types""" login_user_via_session(client, librarian_martigny.user) item = item_lib_martigny assert item.status == ItemStatus.ON_SHELF # test basic behavior cipo_used = CircPolicy.provide_circ_policy( lib_martigny.organisation_pid, lib_martigny.pid, patron_martigny.patron_type_pid, item.item_type_circulation_category_pid) assert cipo_used == circ_policy_short_martigny # add a temporary_item_type on item # due to this change, the cipo used during circulation operation should # be different from the first cipo found. item['temporary_item_type'] = { '$ref': get_ref_for_pid('itty', item_type_on_site_martigny.pid) } item = item.update(data=item, dbcommit=True, reindex=True) cipo_tmp_used = CircPolicy.provide_circ_policy( lib_martigny.organisation_pid, lib_martigny.pid, patron_martigny.patron_type_pid, item.item_type_circulation_category_pid) assert cipo_tmp_used == circ_policy_default_martigny delta = timedelta(cipo_tmp_used.get('checkout_duration')) expected_date = datetime.now() + delta expected_dates = [expected_date, lib_martigny.next_open(expected_date)] expected_dates = [d.strftime('%Y-%m-%d') for d in expected_dates] # try a checkout and check the transaction end_date is related to the cipo # corresponding to the temporary item_type params = dict(item_pid=item.pid, patron_pid=patron_martigny.pid, transaction_user_pid=librarian_martigny.pid, transaction_location_pid=loc_public_martigny.pid) res, data = postdata(client, 'api_item.checkout', params) assert res.status_code == 200 transaction_end_date = data['action_applied']['checkout']['end_date'] transaction_end_date = ciso8601.parse_datetime(transaction_end_date).date() transaction_end_date = transaction_end_date.strftime('%Y-%m-%d') assert transaction_end_date in expected_dates # reset the item to original value del item['temporary_item_type'] item.update(data=item, dbcommit=True, reindex=True)
def test_checkout_default_policy(client, lib_martigny, librarian_martigny_no_email, patron_martigny_no_email, loc_public_martigny, item_type_standard_martigny, item_lib_martigny, json_header, circulation_policies): """Test circ policy parameters""" login_user_via_session(client, librarian_martigny_no_email.user) item = item_lib_martigny item_pid = item.pid patron_pid = patron_martigny_no_email.pid from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1', 'itty1') # checkout res, data = postdata(client, 'api_item.checkout', dict(item_pid=item_pid, patron_pid=patron_pid)) assert res.status_code == 200 actions = data.get('action_applied') loan = actions[LoanAction.CHECKOUT] end_date = loan.get('end_date') start_date = loan.get('start_date') checkout_duration = (ciso8601.parse_datetime(end_date) - ciso8601.parse_datetime(start_date)).days assert checkout_duration >= circ_policy.get('checkout_duration') # checkin res, _ = postdata(client, 'api_item.checkin', dict(item_pid=item_pid, pid=loan.get('pid'))) assert res.status_code == 200
def test_circ_policy_search(app, circulation_policies): """Test finding a circulation policy.""" data = [{ 'library_pid': 'lib1', 'patron_type_pid': 'ptty1', 'item_type_pid': 'itty1', 'cipo': 'cipo2' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty2', 'item_type_pid': 'itty2', 'cipo': 'cipo3' }, { 'library_pid': 'lib2', 'patron_type_pid': 'ptty2', 'item_type_pid': 'itty2', 'cipo': 'cipo1' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty3', 'item_type_pid': 'itty2', 'cipo': 'cipo1' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty1', 'item_type_pid': 'itty2', 'cipo': 'cipo1' }] for row in data: cipo = CircPolicy.provide_circ_policy(row['library_pid'], row['patron_type_pid'], row['item_type_pid']) assert cipo.pid == row['cipo']
def test_item_possible_actions(client, item_on_shelf, user_librarian_no_email, user_patron_no_email): """Possible action changes according to params of cipo""" login_user_via_session(client, user_librarian_no_email.user) item = item_on_shelf patron_pid = user_patron_no_email.pid res = client.get( url_for('api_item.item', item_barcode=item.get('barcode'), patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) actions = data.get('metadata').get('item').get('actions') assert 'checkout' in actions from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1', 'itty1') circ_policy['allow_checkout'] = False circ_policy.update(circ_policy, dbcommit=True, reindex=True) res = client.get( url_for('api_item.item', item_barcode=item.get('barcode'), patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) actions = data.get('metadata').get('item').get('actions') assert 'checkout' not in actions circ_policy['allow_checkout'] = True circ_policy.update(circ_policy, dbcommit=True, reindex=True) assert circ_policy['allow_checkout']
def test_due_soon_loans(client, librarian_martigny_no_email, patron_martigny_no_email, loc_public_martigny, item_type_standard_martigny, item_lib_martigny, json_header, circ_policy_short_martigny): """Test overdue loans.""" login_user_via_session(client, librarian_martigny_no_email.user) item = item_lib_martigny item_pid = item.pid patron_pid = patron_martigny_no_email.pid assert not item.is_loaned_to_patron( patron_martigny_no_email.get('barcode')) assert item.can_delete assert item.available from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy( item.library_pid, patron_martigny_no_email.patron_type_pid, item.item_type_pid) circ_policy['number_of_days_before_due_date'] = 7 circ_policy['checkout_duration'] = 3 circ_policy.update(circ_policy, dbcommit=True, reindex=True) # checkout res = client.post( url_for('api_item.checkout'), data=json.dumps(dict(item_pid=item_pid, patron_pid=patron_pid)), content_type='application/json', ) assert res.status_code == 200 data = get_json(res) loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid') due_soon_loans = get_due_soon_loans() assert due_soon_loans[0].get('pid') == loan_pid # test due date hour checkout_loan = Loan.get_record_by_pid(loan_pid) end_date = ciso8601.parse_datetime(checkout_loan.get('end_date')) assert end_date.minute == 59 and end_date.hour == 23 new_timezone = pytz.timezone('US/Pacific') end_date = ciso8601.parse_datetime( checkout_loan.get('end_date')).astimezone(new_timezone) assert end_date.minute == 59 and end_date.hour != 23 new_timezone = pytz.timezone('Europe/Amsterdam') end_date = ciso8601.parse_datetime( checkout_loan.get('end_date')).astimezone(new_timezone) assert end_date.minute == 59 and end_date.hour != 23 # checkin the item to put it back to it's original state res = client.post( url_for('api_item.checkin'), data=json.dumps(dict(item_pid=item_pid, pid=loan_pid)), content_type='application/json', ) assert res.status_code == 200
def test_extend_possible_actions(client, item_lib_martigny, loc_public_martigny, librarian_martigny_no_email, patron_martigny_no_email, circ_policy_short_martigny): """Extend action changes according to params of cipo.""" login_user_via_session(client, librarian_martigny_no_email.user) item = item_lib_martigny patron_pid = patron_martigny_no_email.pid res, _ = postdata( client, 'api_item.checkout', dict(item_pid=item.pid, patron_pid=patron_pid, transaction_user_pid=librarian_martigny_no_email.pid, transaction_location_pid=loc_public_martigny.pid)) # check the item is now in patron loaned item res = client.get(url_for('api_item.loans', patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) assert data['hits']['total']['value'] == 1 hit = data.get('hits').get('hits')[0].get('item') assert hit.get('barcode') == item.get('barcode') # check the item can be checked-in res = client.get(url_for('api_item.item', item_barcode=item.get('barcode'))) assert res.status_code == 200 data = get_json(res) actions = data.get('metadata').get('item').get('actions', []) assert 'checkin' in actions from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1', 'itty1') circ_policy['number_renewals'] = 0 circ_policy.update(circ_policy, dbcommit=True, reindex=True) res = client.get(url_for('api_item.item', item_barcode=item.get('barcode'))) assert res.status_code == 200 data = get_json(res) actions = data.get('metadata').get('item').get('actions', []) assert 'extend_loan' not in actions assert 'checkin' in actions # reset used objects loan_pid = data.get('metadata').get('loan').get('pid') res, _ = postdata( client, 'api_item.checkin', dict(item_pid=item.pid, pid=loan_pid, transaction_user_pid=librarian_martigny_no_email.pid, transaction_location_pid=loc_public_martigny.pid)) assert res.status_code == 200 circ_policy['number_renewals'] = 1 circ_policy.update(circ_policy, dbcommit=True, reindex=True) assert circ_policy['number_renewals'] == 1
def test_due_soon_loans(client, librarian_martigny, patron_martigny, loc_public_martigny, item_type_standard_martigny, item_lib_martigny, circ_policy_short_martigny): """Test overdue loans.""" login_user_via_session(client, librarian_martigny.user) item = item_lib_martigny item_pid = item.pid patron_pid = patron_martigny.pid assert not get_last_transaction_loc_for_item(item_pid) assert not item.patron_has_an_active_loan_on_item(patron_martigny) assert item.can_delete assert item.available from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy( item.organisation_pid, item.library_pid, patron_martigny.patron_type_pid, item.item_type_pid) circ_policy['reminders'][0]['days_delay'] = 7 circ_policy['checkout_duration'] = 3 circ_policy.update(circ_policy, dbcommit=True, reindex=True) # checkout res, data = postdata( client, 'api_item.checkout', dict( item_pid=item_pid, patron_pid=patron_pid, transaction_location_pid=loc_public_martigny.pid, transaction_user_pid=librarian_martigny.pid, )) assert res.status_code == 200 loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid') due_soon_loans = get_due_soon_loans() assert due_soon_loans[0].get('pid') == loan_pid # test due date regarding multiple timezones checkout_loan = Loan.get_record_by_pid(loan_pid) loan_date = ciso8601.parse_datetime(checkout_loan.get('end_date')) # as instance timezone is Europe/Zurich, it should be either 21 or 22 check_timezone_date(pytz.utc, loan_date, [21, 22]) # should be 14:59/15:59 in US/Pacific (because of daylight saving time) check_timezone_date(pytz.timezone('US/Pacific'), loan_date, [14, 15]) check_timezone_date(pytz.timezone('Europe/Amsterdam'), loan_date) # checkin the item to put it back to it's original state res, _ = postdata( client, 'api_item.checkin', dict(item_pid=item_pid, pid=loan_pid, transaction_location_pid=loc_public_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200
def test_circ_policy_search( app, circ_policy, circ_policy_short, circ_policy_short_library ): """Test Find circ policy""" data = [ { 'library_pid': 'lib1', 'patron_type_pid': 'ptty1', 'item_type_pid': 'itty1', 'cipo': 'cipo2' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty2', 'item_type_pid': 'itty2', 'cipo': 'cipo3' }, { 'library_pid': 'lib2', 'patron_type_pid': 'ptty2', 'item_type_pid': 'itty2', 'cipo': 'cipo1' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty3', 'item_type_pid': 'itty2', 'cipo': 'cipo1' }, { 'library_pid': 'lib1', 'patron_type_pid': 'ptty1', 'item_type_pid': 'itty2', 'cipo': 'cipo1' } ] for row in data: cipo = CircPolicy.provide_circ_policy( row['library_pid'], row['patron_type_pid'], row['item_type_pid'] ) assert cipo.pid == row['cipo']
def test_extend_possible_actions(client, item_lib_martigny, librarian_martigny_no_email, patron_martigny_no_email, circ_policy_short_martigny): """Extend action changes according to params of cipo.""" login_user_via_session(client, librarian_martigny_no_email.user) circ_policy = circ_policy_short_martigny item = item_lib_martigny patron_pid = patron_martigny_no_email.pid res = client.post( url_for('api_item.checkout'), data=json.dumps(dict(item_pid=item.pid, patron_pid=patron_pid)), content_type='application/json', ) res = client.get(url_for('api_item.loans', patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) assert data.get('hits').get('total') == 1 actions = data.get('hits').get('hits')[0].get('item').get('actions') assert 'checkin' in actions from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1', 'itty1') circ_policy['number_renewals'] = 0 circ_policy.update(circ_policy, dbcommit=True, reindex=True) res = client.get(url_for('api_item.loans', patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) assert data.get('hits').get('total') == 1 actions = data.get('hits').get('hits')[0].get('item').get('actions') assert 'extend_loan' not in actions assert 'checkin' in actions loan_pid = data.get('hits').get('hits')[0].get('loan').get('pid') # reset used objects res = client.post( url_for('api_item.checkin'), data=json.dumps(dict(item_pid=item.pid, pid=loan_pid)), content_type='application/json', ) assert res.status_code == 200 circ_policy['number_renewals'] = 1 circ_policy.update(circ_policy, dbcommit=True, reindex=True) assert circ_policy['number_renewals'] == 1
def test_item_possible_actions(client, item_lib_martigny, librarian_martigny, patron_martigny, circulation_policies): """Possible action changes according to params of cipo.""" login_user_via_session(client, librarian_martigny.user) item = item_lib_martigny patron_pid = patron_martigny.pid res = client.get( url_for('api_item.item', item_barcode=item.get('barcode'), patron_pid=patron_pid)) data = get_json(res) assert res.status_code == 200 actions = data.get('metadata').get('item').get('actions') assert 'checkout' in actions from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy(item.organisation_pid, item.library_pid, 'ptty1', 'itty1') original_checkout_duration = circ_policy.get('checkout_duration') if original_checkout_duration is not None: del circ_policy['checkout_duration'] circ_policy.update(circ_policy, dbcommit=True, reindex=True) res = client.get( url_for('api_item.item', item_barcode=item.get('barcode'), patron_pid=patron_pid)) assert res.status_code == 200 data = get_json(res) actions = data.get('metadata').get('item').get('actions') assert 'checkout' not in actions if original_checkout_duration is not None: circ_policy['checkout_duration'] = original_checkout_duration circ_policy.update(circ_policy, dbcommit=True, reindex=True) assert circ_policy.can_checkout
def can_extend(cls, item, **kwargs): """Loan can extend.""" from rero_ils.modules.loans.utils import extend_loan_data_is_valid if 'loan' not in kwargs: # this method is not relevant return True, [] loan = kwargs['loan'] if loan.get('state') != LoanState.ITEM_ON_LOAN: return False, [_('The loan cannot be extended')] patron = Patron.get_record_by_pid(loan.get('patron_pid')) cipo = CircPolicy.provide_circ_policy( item.organisation_pid, item.library_pid, patron.patron_type_pid, item.item_type_circulation_category_pid) extension_count = loan.get('extension_count', 0) if not (cipo.get('number_renewals', 0) > 0 and extension_count < cipo.get('number_renewals', 0) and extend_loan_data_is_valid(loan.get('end_date'), cipo.get('renewal_duration'), item.library_pid)): return False, [_('Circulation policies disallows the operation.')] if item.number_of_requests(): return False, [_('A pending request exists on this item.')] return True, []
def item(item_barcode): """HTTP GET request for requested loans for a library item and patron.""" item = Item.get_item_by_barcode(item_barcode, current_librarian.organisation_pid) if not item: abort(404) loan = get_loan_for_item(item_pid_to_object(item.pid)) if loan: loan = Loan.get_record_by_pid(loan.get('pid')).dumps_for_circulation() item_dumps = item.dumps_for_circulation() patron_pid = flask_request.args.get('patron_pid') if patron_pid: patron = Patron.get_record_by_pid(patron_pid) organisation_pid = item.organisation_pid library_pid = item.library_pid patron_type_pid = patron.patron_type_pid item_type_pid = item.item_type_circulation_category_pid circ_policy = CircPolicy.provide_circ_policy( organisation_pid=organisation_pid, library_pid=library_pid, patron_type_pid=patron_type_pid, item_type_pid=item_type_pid) new_actions = [] # If circulation policy doesn't allow checkout operation no need to # perform special check describe below. if circ_policy.can_checkout: for action in item_dumps.get('actions', []): if action == 'checkout': if (item.number_of_requests() > 0 and item.patron_request_rank(patron) == 1 or item.number_of_requests() <= 0): new_actions.append(action) elif action == 'receive' and item.number_of_requests() == 0: new_actions.append('checkout') item_dumps['actions'] = new_actions return jsonify({'metadata': {'item': item_dumps, 'loan': loan}})
def calculate_notification_amount(notification): """Return amount due for a notification. :param notification: the notification for which to compute the amount. At this time, this is not yet a `Notification`, only a dict of structured data. :return the amount due for this notification. 0 if no amount could be compute. """ # Find the reminder type to use based on the notification that we would # sent. If no reminder type is found, then no amount could be calculated # and we can't return '0' notif_type = notification.get('notification_type') reminder_type_mapping = { NotificationType.DUE_SOON: DUE_SOON_REMINDER_TYPE, NotificationType.OVERDUE: OVERDUE_REMINDER_TYPE } reminder_type = reminder_type_mapping.get(notif_type) if not notif_type or not reminder_type: return 0 # to find the notification due amount, we firstly need to get the # circulation policy linked to the parent loan. location_pid = notification.transaction_location_pid location = Location.get_record_by_pid(location_pid) cipo = CircPolicy.provide_circ_policy( location.organisation_pid, location.library_pid, notification.patron.patron_type_pid, notification.item.holding_circulation_category_pid) # now we get the circulation policy, search the correct reminder depending # of the reminder_counter from the notification context. reminder = cipo.get_reminder(reminder_type=reminder_type, idx=notification.get('context', {}).get( 'reminder_counter', 0)) return reminder.get('fee_amount', 0) if reminder else 0
def test_timezone_due_date(client, librarian_martigny_no_email, patron_martigny_no_email, loc_public_martigny, item_type_standard_martigny, item3_lib_martigny, circ_policy_short_martigny, lib_martigny): """Test that timezone affects due date regarding library location.""" # Login to perform action login_user_via_session(client, librarian_martigny_no_email.user) # Close the library all days. Except Monday. del lib_martigny['opening_hours'] del lib_martigny['exception_dates'] lib_martigny['opening_hours'] = [ { "day": "monday", "is_open": True, "times": [ { "start_time": "07:00", "end_time": "19:00" } ] }, { "day": "tuesday", "is_open": False, "times": [] }, { "day": "wednesday", "is_open": False, "times": [] }, { "day": "thursday", "is_open": False, "times": [] }, { "day": "friday", "is_open": False, "times": [] }, { "day": "saturday", "is_open": False, "times": [] }, { "day": "sunday", "is_open": False, "times": [] } ] lib_martigny.update(lib_martigny, dbcommit=True, reindex=True) # Change circulation policy checkout_duration = 3 item = item3_lib_martigny item_pid = item.pid patron_pid = patron_martigny_no_email.pid from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy( item.library_pid, patron_martigny_no_email.patron_type_pid, item.item_type_pid ) circ_policy['number_of_days_before_due_date'] = 7 circ_policy['checkout_duration'] = checkout_duration circ_policy.update( circ_policy, dbcommit=True, reindex=True ) # Checkout the item res, data = postdata( client, 'api_item.checkout', dict( item_pid=item_pid, patron_pid=patron_pid, transaction_location_pid=loc_public_martigny.pid, transaction_user_pid=librarian_martigny_no_email.pid, ) ) assert res.status_code == 200 # Get Loan date (should be in UTC) loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid') loan = Loan.get_record_by_pid(loan_pid) loan_end_date = loan.get('end_date') # Get next library open date (should be next monday after X-1 days) where # X is checkout_duration soon = datetime.now(pytz.utc) + timedelta(days=(checkout_duration-1)) lib = Library.get_record_by_pid(item.library_pid) lib_datetime = lib.next_open(soon) # Loan date should be in UTC (as lib_datetime). loan_datetime = ciso8601.parse_datetime(loan_end_date) # Compare year, month and date for Loan due date: should be the same! fail_msg = "Check timezone for Loan and Library. \ It should be the same date, even if timezone changed." assert loan_datetime.year == lib_datetime.year, fail_msg assert loan_datetime.month == lib_datetime.month, fail_msg assert loan_datetime.day == lib_datetime.day, fail_msg # Loan date differs regarding timezone, and day of the year (GMT+1/2). check_timezone_date(pytz.utc, loan_datetime, [21, 22])
def test_due_soon_loans(client, librarian_martigny, lib_martigny_data, lib_martigny, patron_martigny, loc_public_martigny, item_type_standard_martigny, item_lib_martigny, circ_policy_short_martigny, yesterday): """Test overdue loans.""" login_user_via_session(client, librarian_martigny.user) item = item_lib_martigny item_pid = item.pid patron_pid = patron_martigny.pid can, reasons = item.can_delete assert can assert reasons == {} assert item.available assert not get_last_transaction_loc_for_item(item_pid) assert not item.patron_has_an_active_loan_on_item(patron_martigny) from rero_ils.modules.circ_policies.api import CircPolicy circ_policy = CircPolicy.provide_circ_policy( item.organisation_pid, item.library_pid, patron_martigny.patron_type_pid, item.item_type_pid) circ_policy['reminders'][0]['days_delay'] = 7 circ_policy['checkout_duration'] = 3 circ_policy.update(circ_policy, dbcommit=True, reindex=True) # Remove library exception date to ensure to not been annoyed by # closed dates. custom_lib_data = deepcopy(lib_martigny_data) custom_lib_data['exception_dates'] = [] lib_martigny.update(custom_lib_data, dbcommit=True, reindex=True) flush_index(LibrariesSearch.Meta.index) # checkout res, data = postdata( client, 'api_item.checkout', dict( item_pid=item_pid, patron_pid=patron_pid, transaction_location_pid=loc_public_martigny.pid, transaction_user_pid=librarian_martigny.pid, )) assert res.status_code == 200 loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid') # To be considerate as 'due_soon', we need to update the loan start date # to figure than start_date occurs before due_date. loan = Loan.get_record_by_pid(loan_pid) start_date = ciso8601.parse_datetime(loan.get('start_date')) loan['start_date'] = (start_date - timedelta(days=30)).isoformat() loan.update(loan, dbcommit=True, reindex=True) due_soon_loans = list(get_due_soon_loans()) assert due_soon_loans[0].get('pid') == loan_pid # test due date regarding multiple timezones checkout_loan = Loan.get_record_by_pid(loan_pid) loan_date = ciso8601.parse_datetime(checkout_loan.get('end_date')) # as instance timezone is Europe/Zurich, it should be either 21 or 22 check_timezone_date(pytz.utc, loan_date, [21, 22]) # should be 14:59/15:59 in US/Pacific (because of daylight saving time) check_timezone_date(pytz.timezone('US/Pacific'), loan_date, [14, 15]) check_timezone_date(pytz.timezone('Europe/Amsterdam'), loan_date) # checkin the item to put it back to it's original state res, _ = postdata( client, 'api_item.checkin', dict(item_pid=item_pid, pid=loan_pid, transaction_location_pid=loc_public_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 # reset lib lib_martigny.update(lib_martigny_data, dbcommit=True, reindex=True)