def test_holding_create(db, es, document, org_martigny, loc_public_martigny, item_type_standard_martigny, holding_lib_martigny_data): """Test holding creation.""" next_pid = Holding.provider.identifier.next() holding = Holding.create(holding_lib_martigny_data, dbcommit=True, reindex=True, delete_pid=True) next_pid += 1 assert holding == holding_lib_martigny_data assert holding.get('pid') == str(next_pid) holding = Holding.get_record_by_pid(str(next_pid)) assert holding == holding_lib_martigny_data fetched_pid = fetcher(holding.id, holding) assert fetched_pid.pid_value == str(next_pid) assert fetched_pid.pid_type == 'hold' search = HoldingsSearch() es_hit = next(search.filter('term', pid=holding.pid).source('pid').scan()) holding_record = Holding.get_record_by_pid(es_hit.pid) assert holding_record.organisation_pid == org_martigny.get('pid') # holdings does not exist assert not Holding.get_holdings_type_by_holding_pid('toto') # clean created data holding.delete(force=True, dbcommit=True, delindex=True)
def test_receive_regular_issue(holding_lib_martigny_w_patterns): """Test holdings receive regular issues.""" holding = holding_lib_martigny_w_patterns assert holding.holding_is_serial issue = holding.receive_regular_issue(dbcommit=True, reindex=True) # test holdings call number inheriting assert issue.issue_inherited_first_call_number == \ holding.get('call_number') assert list(holding.get_items)[0].get('pid') == issue.pid assert issue.location_pid == holding.location_pid assert issue.item_type_pid == holding.circulation_category_pid assert issue.document_pid == holding.document_pid assert issue.holding_pid == holding.pid assert issue.get('status') == ItemStatus.ON_SHELF assert issue.item_record_type == 'issue' assert issue.organisation_pid == holding.organisation_pid assert issue.get('issue', {}).get('regular') assert issue.issue_status == ItemIssueStatus.RECEIVED assert issue.expected_date == '2023-03-01' assert issue.get('enumerationAndChronology') == 'no 73 mars 2023' assert issue.received_date == datetime.now().strftime('%Y-%m-%d') issue_status_date = ciso8601.parse_datetime(issue.issue_status_date) assert issue_status_date.strftime('%Y-%m-%d') == \ datetime.now().strftime('%Y-%m-%d') # test change status_date with status changes issue['issue']['status'] = ItemIssueStatus.CLAIMED new_issues = issue.update(issue, dbcommit=True, reindex=True) assert new_issues.issue_status == ItemIssueStatus.CLAIMED new_issue_status_date = ciso8601.parse_datetime( new_issues.issue_status_date) assert new_issue_status_date > issue_status_date holding = Holding.get_record_by_pid(holding.pid) issue = holding.receive_regular_issue(dbcommit=True, reindex=True) assert issue.get('issue', {}).get('regular') assert issue.issue_status == ItemIssueStatus.RECEIVED assert issue.expected_date == '2020-06-01' assert issue.get('enumerationAndChronology') == 'no 62 juin 2020' assert issue.received_date == datetime.now().strftime('%Y-%m-%d') # test create customized regular issue record = { 'issue': { 'regular': True, 'status': ItemIssueStatus.RECEIVED, 'expected_date': datetime.now().strftime('%Y-%m-%d'), 'received_date': datetime.now().strftime('%Y-%m-%d') }, 'enumerationAndChronology': 'free_text' } holding = Holding.get_record_by_pid(holding.pid) issue = holding.receive_regular_issue(item=record, dbcommit=True, reindex=True) assert issue.get('issue', {}).get('regular') assert issue.issue_status == ItemIssueStatus.RECEIVED assert issue.expected_date == datetime.now().strftime('%Y-%m-%d') assert issue.get('enumerationAndChronology') == 'free_text' assert issue.received_date == datetime.now().strftime('%Y-%m-%d')
def test_item_circulation_dumper(item_lib_martigny): """Test item circulation dumper.""" item = item_lib_martigny item['call_number'] = 'ITEM_MAIN_CN' item['second_call_number'] = 'ITEM_SECOND_CN' holdings = Holding.get_record_by_pid(item.holding_pid) original_holding_data = deepcopy(holdings) holdings['call_number'] = 'HOLDING_MAIN_CN' holdings['second_call_number'] = 'HOLDING_SECOND_CN' holdings.update(holdings, dbcommit=True, reindex=True) # CHECK_1 :: dumped call_numbers are equivalent to item call numbers dumped_data = item.dumps(dumper=ItemCirculationDumper()) assert dumped_data['call_number'] == item['call_number'] item.pop('call_number', None) dumped_data = item.dumps(dumper=ItemCirculationDumper()) assert 'call_number' not in dumped_data assert dumped_data['second_call_number'] == item['second_call_number'] # CHECK_2 :: remove all call_numbers from item, dumped date should # integrate parent holdings call_numbers item.pop('second_call_number', None) dumped_data = item.dumps(dumper=ItemCirculationDumper()) assert dumped_data['call_number'] == holdings['call_number'] assert dumped_data['second_call_number'] == holdings['second_call_number'] # RESET HOLDING RECORD holdings.update(original_holding_data, dbcommit=True, reindex=True)
def test_issues_permissions(client, json_header, holding_lib_martigny_w_patterns, librarian_martigny): """Test specific items issues permissions.""" # receive a regular issue holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) login_user_via_session(client, librarian_martigny.user) res, data = postdata(client, 'api_holding.receive_regular_issue', url_data=dict(holding_pid=holding.pid)) assert res.status_code == 200 data = get_json(res) issue_item = Item.get_record_by_pid(data.get('issue', {}).get('pid')) assert issue_item is not None assert issue_item.issue_is_regular # a regular issue cannot be deleted res = client.get( url_for('api_blueprint.permissions', route_name='items', record_pid=issue_item.pid)) assert res.status_code == 200 data = get_json(res) assert not data['delete']['can']
def test_holding_item_links(client, holding_lib_martigny, item_lib_martigny, item_lib_martigny_data, document, item_type_on_site_martigny, loc_public_martigny, item_lib_saxon_data, loc_public_saxon, item_type_standard_martigny): """Test holding and item links.""" item = deepcopy(item_lib_martigny_data) del item['pid'] item['barcode'] = 'barcode' item = Item.create(item, dbcommit=True, reindex=True) flush_index(HoldingsSearch.Meta.index) assert item.holding_pid == holding_lib_martigny.pid assert item.holding_circulation_category_pid == \ item_type_standard_martigny.pid item2 = deepcopy(item_lib_saxon_data) del item2['pid'] item2 = Item.create(item2, dbcommit=True, reindex=True) flush_index(HoldingsSearch.Meta.index) assert item2.holding_pid != holding_lib_martigny.pid holding = Holding.get_record_by_pid(item2.holding_pid) assert holding.document_pid == document.pid assert holding.circulation_category_pid == item_type_standard_martigny.pid assert Holding.get_document_pid_by_holding_pid(item2.holding_pid) == \ document.pid holdings = list(Holding.get_holdings_pid_by_document_pid(document.pid)) assert holding_lib_martigny.pid in holdings assert item2.holding_pid in holdings assert holding_lib_martigny.get_links_to_me().get('items') assert not holding_lib_martigny.can_delete
def test_holding_tasks( client, holding_lib_martigny, item_lib_martigny, document, loc_public_saxon): """Test delete standard holdings with no items attached.""" # move item to a new holdings record by changing its location item_lib_martigny['location'] = \ {'$ref': 'https://bib.rero.ch/api/locations/loc3'} item = item_lib_martigny.update( item_lib_martigny, dbcommit=True, reindex=True) holdings_pid = holding_lib_martigny.pid # parent holding has no items and it is not automatically deleted. hold = Holding.get_record_by_pid(holdings_pid) assert hold # execute job to delete standard holdings with no attached items. delete_standard_holdings_having_no_items() hold = Holding.get_record_by_pid(holdings_pid) # holdings no longer exist. assert not hold
def test_receive_regular_issue(holding_lib_martigny_w_patterns): """Test holdings receive regular issues.""" holding = holding_lib_martigny_w_patterns issue = holding.receive_regular_issue(dbcommit=True, reindex=True) assert issue.location_pid == holding.location_pid assert issue.item_type_pid == holding.circulation_category_pid assert issue.document_pid == holding.document_pid assert issue.holding_pid == holding.pid assert issue.get('status') == 'on_shelf' assert issue.item_record_type == 'issue' assert issue.organisation_pid == holding.organisation_pid assert issue.get('issue', {}).get('regular') assert issue.issue_status == 'received' assert issue.expected_date == '2023-03-01' assert issue.display_text == 'no 73 mars 2023' assert issue.received_date == datetime.now().strftime('%Y-%m-%d') holding = Holding.get_record_by_pid(holding.pid) issue = holding.receive_regular_issue(dbcommit=True, reindex=True) assert issue.get('issue', {}).get('regular') assert issue.issue_status == 'received' assert issue.expected_date == '2020-06-01' assert issue.display_text == 'no 62 juin 2020' assert issue.received_date == datetime.now().strftime('%Y-%m-%d') # test create customized regular issue record = { 'issue': { 'regular': True, 'status': 'received', 'expected_date': datetime.now().strftime('%Y-%m-%d'), 'received_date': datetime.now().strftime('%Y-%m-%d'), 'display_text': 'free_text' } } holding = Holding.get_record_by_pid(holding.pid) issue = holding.receive_regular_issue(item=record, dbcommit=True, reindex=True) assert issue.get('issue', {}).get('regular') assert issue.issue_status == 'received' assert issue.expected_date == datetime.now().strftime('%Y-%m-%d') assert issue.display_text == 'free_text' assert issue.received_date == datetime.now().strftime('%Y-%m-%d')
def test_holding_delete_after_item_deletion( client, holding_lib_martigny, item_lib_martigny): """Test automatic holding delete after deleting last item.""" for pid in Item.get_all_pids(): if pid != item_lib_martigny.pid: item = Item.get_record_by_pid(pid) Item.delete(item, dbcommit=True, delindex=True) flush_index(ItemsSearch.Meta.index) pid = holding_lib_martigny.pid holding = Holding.get_record_by_pid(pid) assert not holding.can_delete item_lib_martigny.delete(dbcommit=True, delindex=True) flush_index(ItemsSearch.Meta.index) pid = holding_lib_martigny.pid holding = Holding.get_record_by_pid(pid) assert not holding
def test_receive_regular_issue_api(client, holding_lib_martigny_w_patterns, librarian_fully_no_email, librarian_martigny_no_email, system_librarian_sion_no_email): """Test holdings receive regular issues API.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) issue_display, expected_date = holding._get_next_issue_display_text( holding.get('patterns')) # not logged users are not authorized res, data = postdata(client, 'api_holding.receive_regular_issue', url_data=dict(holding_pid=holding.pid)) assert res.status_code == 401 # librarian of another library are not authoritzed to receive issues # for another library. login_user_via_session(client, librarian_fully_no_email.user) res, data = postdata(client, 'api_holding.receive_regular_issue', url_data=dict(holding_pid=holding.pid)) assert res.status_code == 401 # only users of same organisation may receive issues. login_user_via_session(client, system_librarian_sion_no_email.user) res, data = postdata(client, 'api_holding.receive_regular_issue', url_data=dict(holding_pid=holding.pid)) assert res.status_code == 401 login_user_via_session(client, librarian_martigny_no_email.user) res, data = postdata(client, 'api_holding.receive_regular_issue', url_data=dict(holding_pid=holding.pid)) assert res.status_code == 200 issue = get_json(res).get('issue') assert issue.get('enumerationAndChronology') == issue_display assert issue.get('issue').get('expected_date') == expected_date item = { 'issue': { 'regular': True, 'status': ItemIssueStatus.RECEIVED, 'expected_date': datetime.now().strftime('%Y-%m-%d'), 'received_date': datetime.now().strftime('%Y-%m-%d') }, 'enumerationAndChronology': 'free_text' } res, data = postdata(client, 'api_holding.receive_regular_issue', data=dict(item=item), url_data=dict(holding_pid=holding.pid)) assert res.status_code == 200 issue = get_json(res).get('issue') assert issue.get('enumerationAndChronology') == 'free_text' assert issue.get('issue').get('expected_date') == \ datetime.now().strftime('%Y-%m-%d')
def test_holding_item_links(client, holding_lib_martigny, item_lib_martigny, item_lib_martigny_data, document, item_type_on_site_martigny, loc_public_martigny, item_lib_saxon_data, loc_public_saxon, item_type_standard_martigny): """Test holding and item links.""" item = deepcopy(item_lib_martigny_data) del item['pid'] item['barcode'] = 'barcode' item = Item.create(item, dbcommit=True, reindex=True) flush_index(HoldingsSearch.Meta.index) assert item.holding_pid == holding_lib_martigny.pid assert item.holding_circulation_category_pid == \ item_type_standard_martigny.pid item2 = deepcopy(item_lib_saxon_data) del item2['pid'] item2 = Item.create(item2, dbcommit=True, reindex=True) flush_index(HoldingsSearch.Meta.index) assert item2.holding_pid != holding_lib_martigny.pid holding = Holding.get_record_by_pid(item2.holding_pid) assert holding.document_pid == document.pid assert holding.circulation_category_pid == item_type_standard_martigny.pid assert Holding.get_document_pid_by_holding_pid(item2.holding_pid) == \ document.pid holdings = list(Holding.get_holdings_pid_by_document_pid(document.pid)) assert holding_lib_martigny.pid in holdings assert item2.holding_pid in holdings assert holding_lib_martigny.get_links_to_me().get('items') assert not holding_lib_martigny.can_delete # test loan conditions assert holding_loan_condition_filter(holding_lib_martigny.pid) == \ 'standard' with pytest.raises(Exception): assert holding_loan_condition_filter('no pid') assert holding_location(holding_lib_martigny.replace_refs()) == \ 'Library of Martigny-ville: Martigny Library Public Space' assert holding_circulation_category(holding_lib_martigny) == 'standard' holdings = get_holdings_by_document_item_type( document.pid, item_type_standard_martigny.pid) assert holding_lib_martigny.pid == holdings[1].get('pid') assert list(holding_lib_martigny.get_items)[1].get('pid') == \ item_lib_martigny.pid holding_lib_martigny.delete_from_index() assert not holding_lib_martigny.delete_from_index() holding_lib_martigny.dbcommit(forceindex=True) # test item count by holdings pid assert holding_lib_martigny.get_items_count_by_holding_pid == 2
def test_holding_create(db, es_clear, holding_lib_martigny_data): """Test holding creation.""" holding = Holding.create(holding_lib_martigny_data, delete_pid=True) assert holding == holding_lib_martigny_data assert holding.get('pid') == '1' holding = Holding.get_record_by_pid('1') assert holding == holding_lib_martigny_data fetched_pid = fetcher(holding.id, holding) assert fetched_pid.pid_value == '1' assert fetched_pid.pid_type == 'hold'
def test_holding_create(db, es_clear, document, org_martigny, loc_public_martigny, item_type_standard_martigny, holding_lib_martigny_data): """Test holding creation.""" holding = Holding.create(holding_lib_martigny_data, dbcommit=True, reindex=True, delete_pid=True) flush_index(HoldingsSearch.Meta.index) assert holding == holding_lib_martigny_data assert holding.get('pid') == '1' holding = Holding.get_record_by_pid('1') assert holding == holding_lib_martigny_data fetched_pid = fetcher(holding.id, holding) assert fetched_pid.pid_value == '1' assert fetched_pid.pid_type == 'hold' search = HoldingsSearch() holding = next(search.filter('term', pid=holding.pid).scan()) holding_record = Holding.get_record_by_pid(holding.pid) assert holding_record.organisation_pid == org_martigny.get('pid')
def test_holding_delete_after_item_edition(client, holding_lib_saxon, item_lib_saxon, holding_lib_fully): """Test automatic holding delete after item edition.""" item_lib_saxon['location'] = \ {'$ref': 'https://ils.rero.ch/api/locations/loc5'} item_lib_saxon.update(item_lib_saxon, dbcommit=True, reindex=True) flush_index(ItemsSearch.Meta.index) item = Item.get_record_by_pid(item_lib_saxon.pid) assert item.holding_pid == holding_lib_fully.pid holding = Holding.get_record_by_pid(holding_lib_saxon.pid) assert not holding
def test_automatic_item_creation_no_serials(client, json_header, holding_lib_martigny_w_patterns, item_lib_martigny_data, librarian_martigny_no_email): """Test automatically created items are not attached to serials.""" login_user_via_session(client, librarian_martigny_no_email.user) post_url = 'invenio_records_rest.item_list' res, _ = postdata(client, post_url, item_lib_martigny_data) assert res.status_code == 201 item = Item.get_record_by_pid(item_lib_martigny_data.get('pid')) holding = Holding.get_record_by_pid(item.holding_pid) assert holding.pid != holding_lib_martigny_w_patterns.pid assert holding.location_pid == holding_lib_martigny_w_patterns.location_pid assert holding.get('circulation_category') == \ holding_lib_martigny_w_patterns.get('circulation_category')
def test_patterns_quarterly_two_levels(holding_lib_martigny_w_patterns, pattern_quarterly_two_levels_data): """Test pattern quarterly_two_levels.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = pattern_quarterly_two_levels_data['patterns'] # test first issue assert holding.next_issue_display_text == 'Jg. 20 Heft 1 2020' holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg. 20 Heft 2 2020' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg. 26 Heft 3 2026' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'Jg. 29 Heft 3 2029'
def test_patterns_yearly_two_times(holding_lib_martigny_w_patterns, pattern_yearly_two_times_data): """Test pattern yearly two times.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = pattern_yearly_two_times_data['patterns'] # test first issue assert holding.next_issue_display_text == 'Jg. 8 Nov. 2019' holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg. 9 März 2020' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg. 21 Nov. 2032' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'Jg. 27 Nov. 2038'
def test_patterns_yearly_one_level_with_label( holding_lib_martigny_w_patterns, pattern_yearly_one_level_with_label_data): """Test pattern yearly one level with label.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = pattern_yearly_one_level_with_label_data['patterns'] # test first issue assert holding.next_issue_display_text == '29 Edition 2020' holding.increment_next_prediction() assert holding.next_issue_display_text == '30 Edition 2021' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == '55 Edition 2046' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == '67 Edition 2058'
def test_patterns_half_yearly_two_levels(holding_lib_martigny_w_patterns, pattern_half_yearly_two_levels_data): """Test pattern half_yearly_two_levels.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = \ pattern_half_yearly_two_levels_data['patterns'] # test first issue assert holding.next_issue_display_text == 'Année 30 no 84 June 2020' holding.increment_next_prediction() assert holding.next_issue_display_text == 'Année 30 no 85 Dec. 2020' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == 'Année 43 no 110 June 2033' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'Année 49 no 122 June 2039'
def test_bimonthly_every_two_months_two_levels( holding_lib_martigny_w_patterns, pattern_bimonthly_every_two_months_two_levels_data): """Test pattern bimonthly_every_two_months_two_levels.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = \ pattern_bimonthly_every_two_months_two_levels_data['patterns'] # test first issue assert holding.next_issue_display_text == 'Jg 51 Nr 1 Jan. 2020' holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg 51 Nr 2 März 2020' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == 'Jg 55 Nr 3 Mai 2024' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'Jg 57 Nr 3 Mai 2026'
def test_patterns_bimonthly_every_two_months_one_level( holding_lib_martigny_w_patterns, pattern_bimonthly_every_two_months_one_level_data): """Test pattern quarterly_two_levels.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = \ pattern_bimonthly_every_two_months_one_level_data['patterns'] # test first issue assert holding.next_issue_display_text == '47 jan./fév. 2020' holding.increment_next_prediction() assert holding.next_issue_display_text == '48 mars/avril 2020' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == '73 mai/juin 2024' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == '85 mai/juin 2026'
def test_holdings_get(client, item_lib_martigny, item_lib_martigny_masked): """Test record retrieval.""" holding = Holding.get_record_by_pid(item_lib_martigny.holding_pid) item_url = url_for('invenio_records_rest.hold_item', pid_value=holding.pid) list_url = url_for( 'invenio_records_rest.hold_list', q='pid:' + holding.pid) item_url_with_resolve = url_for( 'invenio_records_rest.hold_item', pid_value=holding.pid, resolve=1, sources=1 ) res = client.get(item_url) assert res.status_code == 200 assert res.headers['ETag'] == '"{}"'.format(holding.revision_id) data = get_json(res) assert holding.dumps() == data['metadata'] # Check metadata for k in ['created', 'updated', 'metadata', 'links']: assert k in data # Check self links res = client.get(to_relative_url(data['links']['self'])) assert res.status_code == 200 assert data == get_json(res) assert holding.dumps() == data['metadata'] # check resolve res = client.get(item_url_with_resolve) assert res.status_code == 200 data = get_json(res) assert holding.replace_refs().dumps() == data['metadata'] res = client.get(list_url) assert res.status_code == 200 data = get_json(res) result = data['hits']['hits'][0]['metadata'] assert result.pop('public_items_count') == 1 assert result.pop('items_count') == 2 assert result == holding.replace_refs()
def test_patterns_half_yearly_one_level(holding_lib_martigny_w_patterns, pattern_half_yearly_one_level_data): """Test pattern half_yearly_one_level.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = \ pattern_half_yearly_one_level_data['patterns'] # test first issue assert holding.next_issue_display_text == 'N˚ 48 printemps 2019' holding.increment_next_prediction() assert holding.next_issue_display_text == 'N˚ 49 automne 2019' for r in range(13): holding.increment_next_prediction() assert holding.next_issue_display_text == 'N˚ 62 printemps 2026' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'N˚ 74 printemps 2032'
def dump(self, record, data): """Dump an item instance for circulation. :param record: the record to dump. :param data: the initial dump data passed in by ``record.dumps()``. :return a dict with dumped data. """ # Dump all information about the item data.update(record.replace_refs().dumps()) data = {k: v for k, v in data.items() if v} # Add the inherited call numbers from parent holding record if item # call numbers is empty. if all(k not in data for k in ['call_number', 'second_call_number']): holding = Holding.get_record_by_pid(record.holding_pid) data['call_number'] = holding.get('call_number') data['second_call_number'] = holding.get('second_call_number') data = {k: v for k, v in data.items() if v} return data
def test_patterns_quarterly_two_levels_with_season( holding_lib_martigny_w_patterns, pattern_quarterly_two_levels_with_season_data): """Test pattern quarterly_two_levels_with_season.""" holding = holding_lib_martigny_w_patterns holding = Holding.get_record_by_pid(holding.pid) holding['patterns'] = \ pattern_quarterly_two_levels_with_season_data['patterns'] # test first issue assert holding.next_issue_display_text == \ 'année 2019 no 277 printemps 2018' holding.increment_next_prediction() assert holding.next_issue_display_text == 'année 2019 no 278 été 2018' for r in range(25): holding.increment_next_prediction() assert holding.next_issue_display_text == \ 'année 2025 no 303 automne 2024' # test preview issues = holding.prediction_issues_preview(13) assert issues[-1]['issue'] == 'année 2028 no 315 automne 2027'
def test_item_holding_document_availability( client, document, lib_martigny, holding_lib_martigny, item_lib_martigny, item2_lib_martigny, librarian_martigny, librarian_saxon, patron_martigny, patron2_martigny, loc_public_saxon, circulation_policies, ebook_1_data, item_lib_martigny_data): """Test item, holding and document availability.""" assert item_availablity_status(client, item_lib_martigny.pid, librarian_martigny.user) assert item_lib_martigny.available assert holding_lib_martigny.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available(view_code='global') assert document_availability_status(client, document.pid, librarian_martigny.user) # login as patron with mock.patch('rero_ils.modules.patrons.api.current_patrons', [patron_martigny]): login_user_via_session(client, patron_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() \ == 'short 15 days' # request login_user_via_session(client, librarian_martigny.user) res, data = postdata( client, 'api_item.librarian_request', dict(item_pid=item_lib_martigny.pid, patron_pid=patron_martigny.pid, pickup_location_pid=loc_public_saxon.pid, transaction_library_pid=lib_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 actions = data.get('action_applied') loan_pid = actions[LoanAction.REQUEST].get('pid') assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_martigny.user) holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availability_status(client, document.pid, librarian_martigny.user) # validate request res, _ = postdata( client, 'api_item.validate_request', dict(item_pid=item_lib_martigny.pid, pid=loan_pid, transaction_library_pid=lib_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_martigny.user) assert not item_lib_martigny.available item = Item.get_record_by_pid(item_lib_martigny.pid) holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availability_status(client, document.pid, librarian_martigny.user) login_user_via_session(client, librarian_saxon.user) # receive res, _ = postdata( client, 'api_item.receive', dict(item_pid=item_lib_martigny.pid, pid=loan_pid, transaction_library_pid=lib_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_saxon.user) item = Item.get_record_by_pid(item_lib_martigny.pid) assert not item.available holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_saxon.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availability_status(client, document.pid, librarian_martigny.user) # checkout res, _ = postdata( client, 'api_item.checkout', dict(item_pid=item_lib_martigny.pid, patron_pid=patron_martigny.pid, transaction_library_pid=lib_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 item = Item.get_record_by_pid(item_lib_martigny.pid) assert not item.available assert not item_availablity_status(client, item.pid, librarian_martigny.user) holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_saxon.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availability_status(client, document.pid, librarian_martigny.user) # test can not request item already checked out to patron res = client.get( url_for('api_item.can_request', item_pid=item_lib_martigny.pid, library_pid=lib_martigny.pid, patron_barcode=patron_martigny.get('patron', {}).get('barcode')[0])) assert res.status_code == 200 data = get_json(res) assert not data.get('can_request') end_date = item.get_item_end_date(time_format=None, language='en') """ request second item with another patron and test document and holding availability """ # login as patron with mock.patch('rero_ils.modules.patrons.api.current_patrons', [patron_martigny]): login_user_via_session(client, patron2_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() \ == 'short 15 days' # request second item login_user_via_session(client, librarian_martigny.user) res, data = postdata( client, 'api_item.librarian_request', dict(item_pid=item2_lib_martigny.pid, patron_pid=patron2_martigny.pid, pickup_location_pid=loc_public_saxon.pid, transaction_library_pid=lib_martigny.pid, transaction_user_pid=librarian_martigny.pid)) assert res.status_code == 200 actions = data.get('action_applied') loan_pid = actions[LoanAction.REQUEST].get('pid') assert not item2_lib_martigny.available assert not item_availablity_status(client, item2_lib_martigny.pid, librarian_martigny.user) holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert not holding.available assert not holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert not document.is_available('global') assert not document_availability_status(client, document.pid, librarian_martigny.user)
def test_holding_organisation_pid(org_martigny, holding_lib_martigny): """Test organisation pid has been added during the indexing.""" search = HoldingsSearch() holding = next(search.filter('term', pid=holding_lib_martigny.pid).scan()) holding_record = Holding.get_record_by_pid(holding.pid) assert holding_record.organisation_pid == org_martigny.pid
def test_item_holding_document_availability( client, document, holding_lib_martigny, item_lib_martigny, item2_lib_martigny, librarian_martigny_no_email, librarian_saxon_no_email, patron_martigny_no_email, patron2_martigny_no_email, loc_public_saxon, circulation_policies): """Test item, holding and document availability.""" assert item_availablity_status(client, item_lib_martigny.pid, librarian_martigny_no_email.user) assert item_lib_martigny.available assert item_availability_text(item_lib_martigny) == 'on_shelf' assert holding_lib_martigny.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available(view_code='global') assert document_availablity_status(client, document.pid, librarian_martigny_no_email.user) # login as patron with mock.patch('rero_ils.modules.patrons.api.current_patron', patron_martigny_no_email): login_user_via_session(client, patron_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() \ == 'short 15 days' # request login_user_via_session(client, librarian_martigny_no_email.user) res, data = postdata( client, 'api_item.librarian_request', dict(item_pid=item_lib_martigny.pid, pickup_location_pid=loc_public_saxon.pid, patron_pid=patron_martigny_no_email.pid)) assert res.status_code == 200 actions = data.get('action_applied') loan_pid = actions[LoanAction.REQUEST].get('pid') assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_martigny_no_email.user) assert item_availability_text(item_lib_martigny) == '1 request' holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availablity_status(client, document.pid, librarian_martigny_no_email.user) # validate request res, _ = postdata(client, 'api_item.validate_request', dict(item_pid=item_lib_martigny.pid, pid=loan_pid)) assert res.status_code == 200 assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_martigny_no_email.user) assert not item_lib_martigny.available item = Item.get_record_by_pid(item_lib_martigny.pid) assert item_availability_text(item) == 'in transit (1 request)' holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availablity_status(client, document.pid, librarian_martigny_no_email.user) login_user_via_session(client, librarian_saxon_no_email.user) # receive res, _ = postdata(client, 'api_item.receive', dict(item_pid=item_lib_martigny.pid, pid=loan_pid)) assert res.status_code == 200 assert not item_lib_martigny.available assert not item_availablity_status(client, item_lib_martigny.pid, librarian_saxon_no_email.user) item = Item.get_record_by_pid(item_lib_martigny.pid) assert not item.available assert item_availability_text(item) == '1 request' holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_saxon_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availablity_status(client, document.pid, librarian_martigny_no_email.user) # checkout res, _ = postdata( client, 'api_item.checkout', dict(item_pid=item_lib_martigny.pid, patron_pid=patron_martigny_no_email.pid)) assert res.status_code == 200 item = Item.get_record_by_pid(item_lib_martigny.pid) assert not item.available assert not item_availablity_status(client, item.pid, librarian_martigny_no_email.user) holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert holding.available assert holding_availablity_status(client, holding_lib_martigny.pid, librarian_saxon_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert document.is_available('global') assert document_availablity_status(client, document.pid, librarian_martigny_no_email.user) class current_i18n: class locale: language = 'en' with mock.patch('rero_ils.modules.items.api.current_i18n', current_i18n): end_date = pytz.utc.localize(parser.parse(item.get_item_end_date())) end_date = format_date_filter(end_date, format='short_date') assert item_availability_text(item) == 'due until ' + end_date """ request second item with another patron and test document and holding availability """ # login as patron with mock.patch('rero_ils.modules.patrons.api.current_patron', patron_martigny_no_email): login_user_via_session(client, patron2_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() \ == 'short 15 days' # request second item login_user_via_session(client, librarian_martigny_no_email.user) res, data = postdata( client, 'api_item.librarian_request', dict(item_pid=item2_lib_martigny.pid, pickup_location_pid=loc_public_saxon.pid, patron_pid=patron2_martigny_no_email.pid)) assert res.status_code == 200 actions = data.get('action_applied') loan_pid = actions[LoanAction.REQUEST].get('pid') assert not item2_lib_martigny.available assert not item_availablity_status(client, item2_lib_martigny.pid, librarian_martigny_no_email.user) assert item_availability_text(item2_lib_martigny) == '1 request' holding = Holding.get_record_by_pid(holding_lib_martigny.pid) assert not holding.available assert not holding_availablity_status(client, holding_lib_martigny.pid, librarian_martigny_no_email.user) assert holding_lib_martigny.get_holding_loan_conditions() == 'standard' assert not document.is_available('global') assert not document_availablity_status(client, document.pid, librarian_martigny_no_email.user)
def test_late_expected_and_claimed_issues(holding_lib_martigny_w_patterns, holding_lib_sion_w_patterns, yesterday, tomorrow): """Test automatic change of late expected issues status to late and automatic change to claimed when issue is due""" martigny = holding_lib_martigny_w_patterns sion = holding_lib_sion_w_patterns def count_issues(holding): """Get holdings issues counts. output format: [late_issues_count, claimed_issues_count] """ late_issues = list( Item.get_issues_by_status(issue_status=ItemIssueStatus.LATE, holdings_pid=holding.pid)) claimed_issues = list( Item.get_issues_by_status(issue_status=ItemIssueStatus.CLAIMED, holdings_pid=holding.pid)) return [len(late_issues), len(claimed_issues)] # these two holdings has no late or claimed issues assert count_issues(martigny) == [0, 0] assert count_issues(sion) == [0, 0] # for these holdings records, the next expected date is already passed # system will receive the issue and change its status to late process_late_claimed_issues(dbcommit=True, reindex=True) assert count_issues(martigny) == [1, 0] assert count_issues(sion) == [1, 0] # create a second late issue for martigny and no more for sion sion['patterns']['next_expected_date'] = tomorrow.strftime('%Y-%m-%d') sion.update(sion, dbcommit=True, reindex=True) martigny['patterns']['next_expected_date'] = yesterday.strftime('%Y-%m-%d') martigny.update(martigny, dbcommit=True, reindex=True) process_late_claimed_issues(dbcommit=True, reindex=True) assert count_issues(martigny) == [2, 0] assert count_issues(sion) == [1, 0] # change the acq_status of Martigny holding. # as Martigny holding isn't yet considerate as alive, no new issue should # be generated. The late issue count still the same (=2) martigny = Holding.get_record_by_pid(martigny.pid) martigny_data = deepcopy(martigny) date2 = datetime.now() - timedelta(days=1) martigny['patterns']['next_expected_date'] = date2.strftime('%Y-%m-%d') martigny['acquisition_status'] = 'not_currently_received' martigny.update(martigny, dbcommit=True, reindex=True) process_late_claimed_issues(dbcommit=True, reindex=True) assert count_issues(martigny) == [2, 0] # no new late issue than before # reset Martigny holding martigny.update(martigny_data, dbcommit=True, reindex=True) # -- test the claiming process # create a first claim for an issue and the claim_counts will increment late_issue = list( Item.get_issues_by_status(issue_status=ItemIssueStatus.LATE, holdings_pid=martigny.pid))[0] late_issue['issue']['status_date'] = ( datetime.now(timezone.utc) - timedelta(days=martigny.days_before_first_claim + 1)).isoformat() late_issue.update(late_issue, dbcommit=True, reindex=True) assert late_issue.claims_count == 0 process_late_claimed_issues(create_next_claim=False, dbcommit=True, reindex=True) assert count_issues(martigny) == [1, 1] assert count_issues(sion) == [1, 0] late_issue = Item.get_record_by_pid(late_issue.pid) assert late_issue.claims_count == 1 # create the next claim for an issue and the claim_counts will increment late_issue['issue']['status_date'] = ( datetime.now(timezone.utc) - timedelta(days=martigny.days_before_next_claim + 1)).isoformat() late_issue.update(late_issue, dbcommit=True, reindex=True) process_late_claimed_issues(dbcommit=True, reindex=True) assert count_issues(martigny) == [1, 1] late_issue = Item.get_record_by_pid(late_issue.pid) assert late_issue.claims_count == 2 # No more claims will be generated because the max claims reached process_late_claimed_issues(dbcommit=True, reindex=True) assert count_issues(martigny) == [1, 1] late_issue = Item.get_record_by_pid(late_issue.pid) assert late_issue.claims_count == 2