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')
Exemple #3
0
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']
Exemple #5
0
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
Exemple #7
0
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')
Exemple #8
0
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
Exemple #9
0
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')
Exemple #10
0
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'
Exemple #12
0
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')
Exemple #13
0
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
Exemple #14
0
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'
Exemple #17
0
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'
Exemple #19
0
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'
Exemple #20
0
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'
Exemple #23
0
    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
Exemple #24
0
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'
Exemple #25
0
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
Exemple #27
0
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